Assigning an unsigned value to a signed char

Viewed 264

Simple question on type conversion in C, assume this line of code:

signed char a = 133;

As the max value of a signed char is 128, does the above code have implementation defined behaviour according to the third rule of casting?

if the value cannot be represented by the new type and it's not unsigned, then the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

2 Answers

First of all, 133 is not unsigned. Since it will always fit in an int, it will be of type int, and signed (furthermore in C99+, all unsuffixed decimal constants are signed! To get unsigned numbers you must add U/u at the end).

Second, this isn't a cast but a conversion. A cast in C is explicit conversion (or non-conversion) to a certain type, marked with construct (type)expression. In this case you could write the initialization to use an explicit cast with

signed char a = (signed char)133;

In this case it would not change the behaviour of the initialization.

third, this is indeed an initialization, not an assignment, so it has different rules for what is an acceptable expression. If this initializer is for an object with static storage duration, then the initializer must be a certain kind of compile-time constant. But for this particular case, both assignment and initialization would do the conversion the same way.

Now we get to the point whether the 3rd integer conversion rule applies - for that you need to know what the 2 first ones are:

  1. the target type is an integer type (not _Bool) with the value representable in it (does not apply in this case since as you well know 133 is not representable if SCHAR_MAX is 127)

  2. the target type is unsigned (well it isn't)

so therefore we get to C11 6.3.1.3p3:

  1. Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

The question is whether it has implementation-defined behaviour - yes, the implementation must document what will happen - either how it calculates the result, or which signal it will raise in that occasion.

For GCC 10.2 the manuals state it:

  • The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 and C11 6.3.1.3).

    For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.

The Clang "documentation" is a "little" less accessible, you just have to read the source code...

This is implicit type conversion at assignment. 133 will be copied bit by bit into the variable a . 133 in binary is 10000101 which when copied into a will represent a negative number as, if leading bit is 1 then it represents a negative number. then the actual value of a will be determined by using 2's compliment method which comes out to be -123 (It also depends on how negative numbers are implemented for signed data types).

Related