Why doesn't my mini-mini-construct work in C

What I'm trying to do is make a mask from 1 bit to the end of the left side of the bit set, and the rest is zero, regardless of the size of the variable. I tried the following:

unsigned char x = ~(~0 >> 1);

      

which, for me, should work, whether on char or int, but it doesn't!

For me, the manipulation looks like this:

||||||||
0|||||||
|0000000

      

This is what appears to be the same as a 16-bit integer:

|||||||| ||||||||
0||||||| ||||||||
|0000000 00000000

      

Why doesn't this design work? This gives me zero whether I am trying to assign it to an unsigned char or int.

I am on 50 pages of K&R so I am fairly new. I don't know what literal means, I'm not sure what an "arithmetic" shift is, I don't know how to use the suffix "and I'm pretty damn sure I can't use a structure.

+3


source to share


3 answers


~0

is a zero int

with all bits reversed, which is int

, consisting of all. On a 2s add-on machine, this is -1

. Right-offsetting a -1

will cause sign expansion, so that's ~0 >> 1

all the same.

What you want is a right offset of the quantity unsigned

, which will not cause sign expansion.

~0u >> 1

      

is an unsigned integer with a high-order zero bit and all others are set to 1, so

~(0u >> 1)

      

is an unsigned integer with the high order bit of one and all others set to zero.



Now getting this to work for all data sizes is non-trivial since C converts the operands of integer arithmetic to int

or unsigned int

beforehand. For example,

~(unsigned char)0 >> 1

      

produces the int

result -1

because the unsigned char is "promoted" int

before being applied ~

.

So, to get what you want with all data types, the only way I can see is to use sizeof

to find out how many bytes (or octets) there are in the data.

#include <stdio.h>
#include <limits.h>
#define LEADING_ONE(X)  (1 << (CHAR_BIT * sizeof(X) - 1))
int main(void) {
  printf("%x\n", LEADING_ONE(char));
  printf("%x\n", LEADING_ONE(int));
  return 0;
}

      

+1


source


The general rule for C is that expressions are evaluated on a generic type, in this case (sign) an integer. The score (~ 0) and (~ 0 → 1) are whole integers, and the shift is an arithmetic shift. In your case, this is done with sign expansion, so:

(0xffffffff >> 1) => (0xffffffff)

      

The logical shift will introduce zero from the left, which you expected, so your problem is how to get the compiler to do the logical shift. Try:



unsigned char a = ~0;
unsigned char b = a >> 1;  // this should do a logical shift
unsigned char c = ~b;

      

There are better ways to do what you are trying, but this should help you fix your current problem.

0


source


There are two things that give you unexpected results.

  • You start with 0

    who is seen as signed int

    .
  • Intermediate results are converted to int

    .

If you are working with unsigned char

strategic points, you should be fine.

unsigned char c = ((unsigned char)~0 >> 1);
c = ~c;

      

0


source







All Articles