6

I'm currently up to chapter 2 in The C Programming Language (K&R) and reading about bitwise operations.

This is the example that sparked my curiosity:

x = x & ~077

Assuming a 16-bit word length and 32-bit long type, what I think would happen is 077 would first be converted to:

0000 0000 0011 1111 (16 bit signed int).

This would then be complemented to:

1111 1111 1100 0000.

My question is what would happen next for the different possible types of x? If x is a signed int the answer is trivial. But, if x is a signed long I'm assuming ~077 would become:

1111 1111 1111 1111 1111 1111 1100 0000

following 2s complement to preserve the sign. Is this correct?

Also, if x is an unsigned long will ~077 become:

0000 0000 0000 0000 1111 1111 1100 0000

Or, will ~077 be converted to a signed long first:

1111 1111 1111 1111 1111 1111 1100 0000

...after which it is converted to an unsigned long (no change to bits)?

Any help would help me clarify whether or not this operation will always set only the last 6 bits to zero.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
SpruceMoose
  • 99
  • 1
  • 5
  • 1
    You can probably do this test yourself by either using a debugger to view values or printing out the values yourself. You can also look at the C language specification. Figure out which specification your compiler supposedly implements and then look up the details in the corresponding spec. "Integer promotion" is probably what you want to look for. FWIW, I believe in C that integer promotion should not change the value. So you'd probably get a sign-extended value – rliu Dec 03 '13 at 08:02

2 Answers2

4

Whatever data-type you choose, ~077 will set the rightmost 6 bits to 0 and all others to 1.

Assuming 16-bit ints and 32-bit longs, there are 4 cases:

Case 1

unsigned int x = 077; // x = 0000 0000 0011 1111
x = ~x; // x = 1111 1111 1100 0000
unsigned long y = ~x; // y = 0000 0000 0000 0000 1111 1111 1100 0000

Case 2

unsigned int x = 077; // x = 0000 0000 0011 1111
x = ~x; // x = 1111 1111 1100 0000
long y = ~x; // y = 0000 0000 0000 0000 1111 1111 1100 0000

Case 3

int x = 077; // x = 0000 0000 0011 1111
x = ~x; // x = 1111 1111 1100 0000
unsigned long y = ~x; // y = 1111 1111 1111 1111 1111 1111 1100 0000

Case 4

int x = 077; // x = 0000 0000 0011 1111
x = ~x; // x = 1111 1111 1100 0000
long y = ~x; // y = 1111 1111 1111 1111 1111 1111 1100 0000

See code here. This means the sign extension is done when the source is signed. When the source is unsigned, sign bit is not extended and the left bits are set to 0.

Sufian Latif
  • 13,086
  • 3
  • 33
  • 70
  • But what happens if ~077 is a signed int which is then ANDed with an unsigned long? – SpruceMoose Dec 03 '13 at 07:52
  • What about: int x = 077; x = ~x; unsigned long y = x; What is y? – SpruceMoose Dec 03 '13 at 07:58
  • OK, I think I've got it. But what is the point of sign extension when converting from signed to an unsigned, as in case 3? Do you know where I can find the actual C specifications for this? – SpruceMoose Dec 03 '13 at 09:54
  • 1
    Found [this](http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Data/signExt.html) after some googling, hope it helps :) And "_When an integer with a negative sign is promoted to an unsigned integer of the same or larger type, it is first promoted to the signed equivalent of the larger type, then converted to the unsigned value._" from [here](http://docs.oracle.com/cd/E19205-01/819-5265/bjamz/index.html). – Sufian Latif Dec 03 '13 at 10:07
2
 x = x & ~077    //~077=11111111111111111111111111000000(not in every case)

~077 is a constant evaluated at the complie time so its value will be casted according to the value of x at the compile time so the AND operation will always yield to last 6 bits of x to 0 and the remaining bits will remain whatever they were before the AND operation. Like

//let x=256472--> Binary--> 0000 0000 0000 0011 1110 1001 1101 1000
 x = x & ~077;
// now x = 0000 0000 0000 0011 1110 1001 1100 0000 Decimal--> 256448

So the last 6 bits are changed to 0 irrespective of the data type during the compile time remaining bits remain same. And in knr it is written there The portable form involves no extra cost, since ~077 is a constant expression that can be evaluated at compile time.

APan
  • 364
  • 1
  • 10