Search code examples
ctypescastingundefined-behaviorsign

How does integer promotion work on C Cast?


I've got bitten by an unexpected integer promotion and made me wonder. Is it consistent across compilers whether promotion happens before explicit casting?

Let me explain. Having a signed 8bit variable such as

int8_t s8a = -128; //<-- 0x80

Assigning into an unsigned 16 as uint16_t s16b = s8a + 1; I would expect a promotion to a larger integer 0xFF81 then assigned, this is a common mishap and is contemplated on documents like MISRA C. But explicitly casting to an unsigned type in a way like uint16_t s16b = (uint16_t)s8a I would have expected s8a to immediatly lose its "signedness" and then zero-extend to 16bit as to give 0x0080 but actually the opposite happens, as it gets sign-extended then lose its signedness when casted and assigned giving 0xFF80.

Is this behavior standard or another undefined behavior of C?


Solution

  • This is not related to integer promotion, but to a type conversion. In your case the process is well defined by the C11 Standard - 6.3.1.3 Signed and unsigned integers (p2):

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

    So here 0xFF80 = 0xFFFF + (-128) + 1, as 0xFFFF is the maximum that can be represented in uint16_t.