Truncating int to char - is it defined?

unsigned char a, b; b = something(); a = ~b; 

The static analyzer complained about truncation in the last line, presumably because b pushed to int before its bits are inverted, and the result will be of type int.

I'm only interested in the last byte of the advanced int - if b was 0x55, I need a be 0xAA. My question is, does the C specification talk about how truncation happens , or is this implementation defined / undefined? Is it guaranteed that a will always be assigned the value that I expect, or can it go wrong on the appropriate platform?

Of course, distinguishing the result before the assignment, it will disable the static analyzer, but I want to know if this warning can be ignored at all.

+4
source share
5 answers

Truncation occurs as described in 6.3.1.3/2 C99 Standard

... if the new type is unsigned, the value is converted by repeatedly adding or subtracting one larger than the maximum value that can be represented in the new type until the value is in the range of the new type.


Example for CHAR_BIT == 8, sizeof (unsigned char) == 1, sizeof (int) == 4

So, 0x55 is converted to int , to 0x00000055, then reset to 0xFFFFFFAA and

  0xFFFFFFAA
     + 0x00000100 / * UCHAR_MAX + 1 * /
     ------------
       0xFFFFFEAA

     ... repeat lots and lots of times ...

       0x000000AA

or, as usual 0xAA , as you would expect

+4
source

The C standard indicates this for unsigned types:

A calculation involving unsigned operands can never be overflowed, since a result that cannot be represented by an unsigned integer type is equal to a reduced modulus number, which is one greater than the largest value that a result type can represent.

In this case, if your unsigned char is 8 bits, this means that the result will be reduced modulo 256, which means that if b was 0x55 , a would actually be in the form 0xAA .

But keep in mind that if an unsigned char wider than 8 bits (which is completely legal), you will get a different result. To ensure that you can get 0xAA as a result, you can use:

 a = ~b & 0xff; 

(Bitwise and should be optimized on platforms where unsigned char is 8 bits).

Note also that if you use a signed type, the result is determined by the implementation.

+9
source

He will behave the way you want it. It is safe to use value.

+1
source

Let's look at the case of a Win32 machine.
An integer is 4 bytes, and converting it to char will result in exactly the same as if 3 bytes remained.

When you convert char to char, it doesn't matter what it is being promoted to.
~b will add 3 bytes at the left change 0s to 1 and then remove... It does not affect your one right byte.

The same concept applies to different architectures (whether it is a 16-bit or 64-bit machine)

Assuming it's a little endian

0
source

This sample code is safe. But there are reasons to warn against poor operator use.

The reason for this is that ~ on small integer variables is a potential error in more complex expressions due to implicit whole promotions in C. Imagine if you had an expression like

a = ~b >> 4;

It will not shift at zeros, as you might expect.

If your static analyzer is configured to enable MISRA-C, for example, you will receive this warning for each ~ operator, because MISRA forces the result of any operation with small integer types to be explicitly indicated in the expected type, unsigned char in this case .

0
source

All Articles