Working with Memory Bits in C

A bit is the smallest possible unit of storage, and can be set to either one or zero. In C, we can manipulate individual bits of data using the bitwise operators. The shift operators can move a bit in a variable to the right or the left by a specified number of positions. The << operator shifts bits to the left; shifting a bit left by one is the same multiplying by two.

#include <stdio.h>

int main(void){

    int a = 1;

    for(int i = 0; i < 8; i ++){
        printf("%d\t", a  <<  i);
    }

    return 0;

}

The right shift operator, >>, is similar to dividing an integer variable by a power of 2. Again, left shifting an integer by n places has the effect of multiplying it by 2^n, and right-shifting an integer has the effect of dividing it by 2^n. Things get a bit more complicated when we start looking at negative numbers, but for now, let’s keep it simple.

#include <stdio.h>

int main(void){

    int a = 255;
    
    //note that output is odd
    for(int i = 7; i > 0; i--){
        printf("%d\t", a >> i);
    }        

    return 0;

}

Eight bits together for a byte, represent in C by the data type char.

The ones complement operator, also know as the NOT operator, also known as the invert operator, is a unary operator that returns the inverse of its operand, meaning that it turns on all the off bits and turns off all the on bits.

#include <stdio.h>

int main(void){

    unsigned char c = 0;
    
    //prints 0
    printf("%d\n", c);

    c = ~c;

    //prints 255
    printf("%d\n", c);

    return 0;

}

Using the NOT operator, we can turn a positive number into a negative number by taking the two’s complement of the binary number. Basically, we flip all the bits and add one to arrive at the negative complement of a positive number.

#include <stdio.h>


int main(void){

    int i = 73;
    int j = ~i + 1;

    printf("%d\t", i);

    printf("%d\t", j);


    return 0;

}

 

The bitwise OR operator, also known as the inclusive OR operator, compares two operands. If one or the other bit is a 1, the result is 1.

#include <stdio.h>

int main(void){

    unsigned char c, d, e;

    //c = 1
    c = 1 << 0;

    printf("c = %d\t", c);
    
    //d = 2
    d = 2 << 0;

    printf("d = %d\t", d);

    // c or (inclusive) d
    // = 3
    e = c | d;

    printf("e = %d\t", e);
    
    return 0;

}

Typically the bitwise OR operator is used to turn on a bit. For instance, we could make sure all numbers are odd by turning on their least significant bit.

#include <stdio.h>

int main(void){

    unsigned char nums[] = {42, 10, 161, 53, 80, 73, 47, 110};
    
    int i = 0;

    for(i = 0; i < 8; i++){
        printf("%d\t", nums[i]);
    }

    printf("\n\n");

    //make all numbers odd
    for(i = 0; i < 8; i++){
        nums[i] = nums[i] | 1;
    }

    for(i = 0; i < 8; i++){
        printf("%d\t", nums[i]);
    }

    
    printf("\n\n");

    return 0;

}

Thus, we see that it is possible to turn on individual bits with a combination of the OR operator and the << operator.

#include <stdio.h>

int main(void){

    unsigned char c = 0;

    printf("c = %d\n", c);

    c = 1 << 0;

    //prints out 1
    printf("c = %d\n", c);

    c = 1 << 7 | 1 << 6;

    //prints out 192
    printf("c = %d\n", c);

    c |= 1 << 0;

    //prints out 193
    printf("c = %d\n", c);

    return 0;


}

The AND operator, &, compares two bits. If they are both 1, the result is 1. If either or both are 0, the result is 0. Anding is used to mask, or isolate, sections of binary numbers as well as to turn off specific bits.

#include <stdio.h>

int main(void){

    char c = 0;
    char d, e;

    //c = 64 + 16
    c = 1 << 6 | 1 << 4;
//prints 80
    printf("c = %d\n", c);

    //leaves 4th bit on
    d = c & 1 << 4;
    //leaves 6th bit on
    e = c & 1 << 6;

//prints 16
    printf("d = %d\n", d);
//prints 64
    printf("e = %d\n", e);
    

    return 0;

}

Essentially, the & operator can be used as a sort of subtraction operator, and the | operator can be used as a sort of addition operator. We should understand here that really we are not adding or subtracting anything, we are just turning things on and off mechanistically, and then logically associating the results with mathematical output. After all, the computer does not understand gain or loss, it’s just flipping switches.

#include <stdio.h>

int main(void){

    char c = 10;
    
    char d, e;

    printf("c = %d\n", c);

    //turns off nothing but the second
    //bit
    d = c & ~(1 << 1);
    //turns off everything but
    //the second bit
    e = c & (1 << 1);

    printf("d = %d\n", d);
    printf("e = %d\n", e);    

    return 0;

}

Well, this is enough shenanigans for one day; take a look at my author’s page on Amazon: http://www.amazon.com/Al-Jensen/e/B008MN382O/

 

 

 

 

 

Advertisements

Introduction to Bitwise Operators

Bitwise operators operate on the bits in integer values. There are six bitwise operators in all:

& Bitwise AND operator

| Bitwise OR operator

^ Bitwise EOR (Exclusive Or) operator

~ Bitwise NOT operator

>> Bitwise shift right operator

<< Bitwise shift left operator

The ~ operator is a unary operator; all of the other bitwise operators are binary operators. The bit-not ~ operator is thus perhaps the simplest example. The ~ operator flips the bits of its operand, changing the 1 bits to 0 and the 0 bits to 1.

#include <stdio.h>

int main(void){
    
    unsigned int i = 0;

    printf("%u\n", ~i);
    printf("%u\n", i);
    
    return 0;
    
}

The shift operators shift the bits in the left operand by the number of positions specified by the right operand. The left shift operator, <<, moves the bits to the left. Arithmetically, the left-shift operator is equivalent to multiplication by a power of two.

In the following program, we will shift a single 1 bit to the left to produce powers of two.

#include <stdio.h>

int main(void){
    
    unsigned int i = 1;
    int j = 0;
    
    for(j; j<8; j++){
        printf("%d\t", 1 << j);
    }

    putchar('\n');

    return 0;
    
}

The right shift operator moves bits to the right. This is an operation best done on unsigned integers.

#include <stdio.h>

int main(void){
    
    unsigned char i = 16;
    
    printf("%d\n", 16);

    i = i >> 2;

    printf("%d\n", 16 >> 2);

    i = i >> 2;

    printf("%d\n", 16 >> 4);

    return 0;

}

We can also use the binary bitwise operators in assignments, excluding, of course, the unary operator ~.

#include <stdio.h>

int main(void){

    int i = 1;
    int j = 1;
    i <<= 3;

    printf("i = %d\n", i);

    i >>= 2;

    printf("i = %d\n", i);

    return 0;

}

The bitwise AND operator, &, examines the bits of its two operands in parallel, and places a one in the position where both bits are 1, and a zero in all other positions. The bitwise OR operator, |, places a one in any position where either operand has a one.

#include <stdio.h>

int main(void){

    int i = 1;
    int j = 1;
    int k = 1;

    printf("1 << 7 = %d \t 1 << 6 = %d\n", 1 << 7, 1 << 6);
    printf("3 << 6 = %d \n", 3 << 6);
    printf("(1 << 7) + (1 << 6) = %d\n",
            (1 << 7) + (1 << 6));

    i <<= 7;
    j <<= 6;

    k = i | j;

    printf("i = %d \t j = %d\n", i, j);
    printf("k = i | j\n");
    printf("k = %d\n", k);

    k &= j;

    printf("k &= j\n");
    printf("k = %d\n", k);

    return 0;

}

Bitwise operators might seem a bit academic, but they’re used often enough. One use is to store multiple values in a single variable, which is how Linux file permissions are stored.