|
| 1 | +--- |
| 2 | +title: C Pro Lecture 22 |
| 3 | +author: Pratyaksh Gautam |
| 4 | +code: cs0.101 |
| 5 | +number: 22 |
| 6 | +--- |
| 7 | + |
| 8 | +## Preprocessor macros: conditionals |
| 9 | + |
| 10 | +We can use conditionals even in the preprocessing stage by using macro conditionals: |
| 11 | +```c |
| 12 | +#ifdef DEBUG |
| 13 | + printf("We are debugging!\n"); |
| 14 | +#endif |
| 15 | +``` |
| 16 | + |
| 17 | +If we either at a line at at the top, `#define DEBUG 1`, or if we compile using the following command then we the `printf` statement is executed and we get the output: |
| 18 | +``` |
| 19 | +$ gcc -DDEBUG debug.c |
| 20 | + We are debugging! |
| 21 | + ``` |
| 22 | + |
| 23 | + The code is replaced *before* compilation by the preprocessor, so if `DEBUG` is not defined, then the code sent to the compiler from the preprocessor does not have the line containing the `printf` statement at all. |
| 24 | + The inclusion of that line is a **compile-time decision**. |
| 25 | + This can be very convenient to manage debugging of the program while still keeping it production-ready. |
| 26 | + |
| 27 | +## Loop invariants |
| 28 | + |
| 29 | +Loop invariants refer to a 'property' of the code which is true for every iteration, and we maintain this throughout the successive iterations. What this means is that at the beginning of every iteration of the loop, we have a certain fact we know to be true, and we can use this for the logic of the loop. |
| 30 | +By the end of the iteration we ensure that the invariant will be true for the next iteration too, so we can use it again in the next iteration. |
| 31 | + |
| 32 | +It is important to understand that loop invariants are not a feature of the C language, but just a concept that we use in order to keep better track of the logic of our code in a loop. |
| 33 | + |
| 34 | +## More on assertions |
| 35 | + |
| 36 | +We have seen assertions in the past and understand their use case. It is important to notice that assertions are **run-time decisions**. |
| 37 | +We can use assertions in conjunction with the concept of our loop invariants too, checking that the loop invariant is true at the beginning of every loop. |
| 38 | +Since the assertion fails and aborts the program telling us where we went wrong if our invariant is not valid, it can be very helpful in debugging. |
| 39 | + |
| 40 | +*Note: If we wish, we can also disable assertions by defining the macro `NDEBUG`.* |
| 41 | + |
| 42 | +## bitwise operators |
| 43 | + |
| 44 | +At the hardware level, the smallest data size that we can read and write is 1 byte (8 bits). |
| 45 | +However there are also operations that we can and may want to conduct on individual bits, which are known as bitwise operations. |
| 46 | +These include bitwise `AND`, `OR`, `XOR`, etc. Their effects can be represented using familiar truth tables. |
| 47 | + |
| 48 | +``` |
| 49 | +10000100 AND 01000110 = 00000100 |
| 50 | +10000100 OR 01000110 = |
| 51 | +10000100 XOR 01000110 = |
| 52 | +``` |
| 53 | + |
| 54 | +### bitwise shifts |
| 55 | +We can also shift the bits to the left or the right. Consider the left shift `<<` in the following situation |
| 56 | +``` |
| 57 | +[ b7 b6 b5 b4 b3 b2 b1 b0 ] |
| 58 | +<< //shift by one |
| 59 | +[ b6 b5 b4 b3 b2 b1 b0 00 ] // b7 "falls off" |
| 60 | +
|
| 61 | +[ b7 b6 b5 b4 b3 b2 b1 b0 ] |
| 62 | +>> //shift by one |
| 63 | +[ 00 b7 b6 b5 b4 b3 b2 b1 ] // b7 "falls off" |
| 64 | +``` |
| 65 | + |
| 66 | +The above logic is perfectly valid for unsigned integers, but because of the way that we represent signed integers means that it isn't so clear cut for signed integers. |
| 67 | + |
| 68 | +## A set of function to print the bit representation of a number |
| 69 | + |
| 70 | +```c |
| 71 | +void readBit(int N, int pos) |
| 72 | +{ |
| 73 | + unsigned int mask; |
| 74 | + mask = 1 << pos; |
| 75 | + return (N & mask)? 1: 0; |
| 76 | +} |
| 77 | +``` |
| 78 | +The above functions takes a number `N` and returns its `pos`'th bit. |
| 79 | +Note that `mask = 1 << pos` gives a bitstring such that all its bits are `0` except the bit at the `pos`'th position. |
| 80 | +So when we do an `AND` operation against `mask`, all but the `pos`'th bit will definitely output a `0`, and the `pos`'th bit of N will output whatever its own value is. |
| 81 | +Thus, we just use the ternary operator to return `0` if that bit is `0`, and `1` otherwise. |
| 82 | +
|
| 83 | +```c |
| 84 | +void printBits(int N) |
| 85 | +{ |
| 86 | + printf("(%d)_2 : ", N); |
| 87 | + for (int i = 8 * sizeof(int); i >= 0; --i) { |
| 88 | + printf("%d", readBit(N, i); |
| 89 | + } |
| 90 | + printf("\n"); |
| 91 | +} |
| 92 | +``` |
| 93 | +Now this function just calls the above function, and prints the relevant bits in order. |
0 commit comments