Confusion

logical operators

  • ||, &&, !, which treat any nonzero argument as representing TRUE and argument 0 as representing FALSE. And then they return either 1 or 0, indicating a result of either TRUE or FALSE, respectively.

  • A second important distinction between the logical operators ‘&&’ and ‘||’
    versus their bit-level counterparts ‘&’ and ‘|’ is that the logical operators do not
    evaluate their second argument if the result of the expression can be determined
    by evaluating the first argument.

1
2
3
4
5
6
7
8
//Rounding toward zero
int divide_power2(int x, int k){
int is_neg = INT_MIN & x;
int bias = (1<<k)-1;
//if is_neg is false, (x = x + (1 << k) - 1) would not be execute
is_neg && (x = x + bias);
return x>>k;
}

unsigned and two’s complement

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stdio.h>
#include<assert.h>
/*
* Return 1 when x can be represented as an n-bit, 2’s-complement
* number; 0 otherwise
* Assume 1 <= n <= w
*/

int fit_bits(int x, int n){
int w = sizeof(int) << 3;
return x==(x<<(w-n)>>(w-n));
}

int main(){
assert(fit_bits(0b010, 3));
assert(!fit_bits(0b010, 2));
}

Fatal

Some possibly nonintuitive behavior arises due to C’s handing of expressions containing combinations of signed and unsigned quantities.

**When an operation is preformed where one operand is signed and the other is unsigned, C implicitly casts the signed argument to unsigned. **

As an example, Since sizeof would return a size_t type, the int type of maxbytes will be implicitly casts to be unsinged. Hence no matter how small the maxbytes is, the condition all way is true and call the function memcpy().

1
2
3
4
void copy_int(int val, void *buf, int maxbytes) {
if (maxbytes-sizeof(val) >= 0)
memcpy(buf, (void *) &val, sizeof(val));
}

So we can rewrite the condition to be maxbytes >= sizeof(val)

Trick

  • x -> -x

    ~x + 1

mask

We often use a mask to extract the special bits in a value. We create a mask, its corresponding bits are 1 and the other bits are zeros.

1
2
3
4
5
6
int any_odd_one(unsigned x)
{
int mask = 0xAAAAAAAA;
//extract all odd numbers of x and use ^ to compare whether all odd numbers are 1
return !((mask & x) ^ mask);
}

logical and arithmetic right shift

1
2
3
4
5
6
int lower_one_mask(int n){
int mask = 1<<31;
mask = mask >> (n-1);//arthmetic right shift
mask = (unsigned)mask >> 31 - (n-1);//logical right shift
return mask;
}

Representations of number In C

  • Decimal

    int x=10;

  • Octal:

    int x = 012;

  • Hexadecimal

    int x = 0xa;

  • Binary

    int x = 0b1010