3

I don't think I fully understand what's happening in the c compiler when I'm left shifting a signed char. I'm initializing it with the value 0x8d << 3, and it gives me a warning: overflow in implicit constant conversion. I'm assuming it's because it's giving too big of a value for a char, however when I do it out by hand I'm getting 104 as an answer.

So does that mean when the value is being shifted it's doing

10001101 << 3 = 10001101000

and not

10001101 << 3 = 01101000

Figured it out, but this was the code:

signed char testChar = 0x8d << 3;
printf("testChar : %d\n", testChar);

Just had to initialize it normally then shift it on another line, super simple stuff.

3
  • The warning is correct, you are creating a compile time constant that overflows a character (8 bit quantity) upon creation. Commented Feb 5, 2016 at 0:04
  • @M.M: sorry, I misread. Commented Feb 5, 2016 at 0:16
  • Please update your question to show us your actual code. Also, you say you got a warning, but you haven't told us what value is actually stored. I expect it's 104. Commented Feb 5, 2016 at 0:19

2 Answers 2

1

You question is confused: are you initializing a signed char with the value 0x8d << 3? This is clearly implementation defined as the value is outside the range of the type and the type is signed. The compiler issues a warning because the loss of precision is explicit.

Conversely, if you mean by left shifting a signed char, left shifting a signed char that has a value of 0x8d, this is again incorrect: unless char has more than 8 bits, a signed char cannot have a value of 0x8d. It can have a value of -115 that has the same bit pattern. Left shifting this will be computed this way:

  • the char value is first promoted to int.
  • the int value is left shifted by 3 but positions: this is equivalent to multiplying by 8.
  • if the value is negative, the Standard says the behavior is undefined, but most current processors using 2s complement representation for negative values will just produce the same result as multiplying by 8.

The resulting value is -920. This value does not fit in a char. Storing it to a char is implementation defined. The most likely result is a char value of 104.

EDIT

You posted the actual code:

signed char testChar = 0x8d << 3;
printf("testChar : %d\n", testChar);

If char is 8 bits, the assignment has implementation defined behavior because 1128 is outside the range of type signed char (-128..127), the behavior on most modern processors is to mask off the high order bits and store the 8 low order bits into the destination byte as if it were an unsigned char. In your case, the result is 1128 & 255 -> 104.

Sign up to request clarification or add additional context in comments.

3 Comments

Ya guess I just have a bad understanding as to when to use bitwise operators. Just had to initialize the char as 0x8d then on another line shift it, got it printing the correct answer now.
initializing the char to 0x8d is incorrect, the value is outside the range of a signed char. Left shifting it by any amount is undefined behavior because the value is negative, but for most current processors, the result is the same as multiplying by 8.
@Lychosand: That didn't solve your problem. It just silenced the compiler warning.
0

You haven't shown your actual code (see below), but you've provided enough information to infer it:

signed char c = 0x8d << 3;

The constant 0x8d is of type int. Left-shifting it by 3 bits yields the value 0x468, or equivalently 1128.

The initialization implicitly converts that value from int to signed char. Since the value is outside the range of signed char (which presumably has a range of -128 to +127, unless you're on a very odd system), the result is implementation-defined. Typically the high-order bits are discarded, which would yield a result of 0x68, or 104.

The compiler is warning you that you're converting the value 1128 to signed char, which isn't big enough to hold it.

Perhaps you were expecting 0x8d to be of type signed char? It isn't. The type of an expression is almost always determined by the expression itself, not by the context in which it appears. Integer constants, either decimal, hexadecimal, or octal, are always of type int, unless they exceed the value of INT_MAX, which is at least 32767 (and probably 2147483647). (Or unless they have a suffix like L or U, but that's not relevant here.)

UPDATE :

You've shown us your original code:

signed char testChar = 0x8d << 3;
printf("testChar : %d\n", testChar);

I would expect this to produce a warning, since the value 1128 that you're using to initialize testChar causes an overflow. The value stored in testChar is implementation-defined, but it's very likely to be 104, the result of discarding the high-order bits.

If you split the shift into a separate assignment:

signed char testChar = 0x8d;
testChar = testChar << 3;

then I'd expect the same result. But the value 0x8d is too big to be stored in a signed char, so the conversion yields an implementation-defined result -- most likely -115. And a left-shift on a negative value has undefined behavior -- but again, it will probably yield -920, which when converted to signed char will probably give you 104.

Ultimately, the solution to your problem is to do something other than what you're trying to do. The value 0x8d << 3 will not fit into a signed char, and any attempt to make it fit is bound to cause problems. By tweaking the code, you might manage to silence the compiler's warnings, but you're still doing things that don't make sense.

6 Comments

Ya you're on the money, I understand the whole range thing which I find strange how for the question I'm meant to use a signed char. I'm still giving the char a value of 0x8d and it's compiling and giving me the correct answer, 104 now which is strange.
See my updated answer. All you've done is hide some information from the compiler, so it's no longer able to warn about the overflow.
@chqrlie: Nitpick handled.
Actually, you updated answer is incorrect, promoting the signed char to int does not yield 141, but -115, which invokes undefined behavior upon left shifting. The compiler no longer complains, but the code now has defined behavior... Who can you trust?
@KeithThompson: I fixed the backticks, left shift of a negative value has undefined behavior, and final conversion yields 104, not -104.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.