Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Truncating an int to char - is it defined?

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

A static analyzer complained of truncation in the last line, presumably because b is promoted to int before its bits are flipped and the result will be of type int.

I am only interested in the last byte of the promoted int - if b was 0x55, I need a to be 0xAA. My question is, does the C spec say anything about how the truncation happens, or is it implementation defined/undefined? Is it guaranteed that a will always get assigned the value I expect or could it go wrong on a conforming platform?

Of course, casting the result before assigning will silence the static analyzer, but I want to know if it is safe to ignore this warning in the first place.

like image 999
Amarghosh Avatar asked May 04 '11 10:05

Amarghosh


People also ask

What is integer truncation?

Truncation is a method of approximating numbers. It is easier than rounding, but does not always give the best approximation to the original number. Truncation is used in computing when division is done with integers and the answer must be an integer. The number e is. e = 2.718281828459045....

Does casting truncate?

2. Truncation Using Casting. If our double value is within the int range, we can cast it to an int. The cast truncates the decimal part, meaning that it cuts it off without doing any rounding.

How do you shorten a Cstring?

To truncate a string in C, you can simply insert a terminating null character in the desired position. All of the standard functions will then treat the string as having the new length. Save this answer.


1 Answers

The C standard specifies this for unsigned types:

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

In this case, if your unsigned char is 8 bits, it means that the result will be reduced modulo 256, which means that if b was 0x55, a will indeed end up as 0xAA.

But note that if unsigned char is wider than 8 bits (which is perfectly legal), you will get a different result. To ensure that you will portably get 0xAA as the result, you can use:

a = ~b & 0xff;

(The bitwise and should be optimised out on platforms where unsigned char is 8 bits).

Note also that if you use a signed type, the result is implementation-defined.

like image 197
caf Avatar answered Sep 22 '22 13:09

caf