Search code examples
ctype-conversionimplicit-conversion

Clarification on assigning hexadecimal constant to a variable of type `signed`


I am reading Jans Gustedt's "Modern C". In a discussion about how the types for numerical literals are determined, he writes about the common pitfall of assigning 0xFFFFFFFF to a signed variable:

A common error is to try to assign a hexadecimal constant to a signed with the expectation that it will represent a negative value. Consider a declaration such as int x = 0xFFFFFFFF. This is done under the assumption that the hexadecimal value has the same binary representation as the signed value −1. On most architectures with 32-bit signed, this will be true (but not on all of them); but then nothing guarantees that the effective value +4294967295 is converted to the value −1.

I want to clarify the meaning of the bolded statement. Does the statement merely state that

  • The simple fact that not all architectures have 32-bit signed integers implicitly means nothing guarantees the conversion from +4294967295 to -1?

Or, is it trying to make the point that

  • Even on architectures with 32-bit signed, nothing guarantees that the effective value +4294967295 is converted to -1?

If the latter, why would this be? Wouldn't the fact that the hexadecimal value has the same bit representation as -1 on architectures with 32-bit signed guarantee that the conversion will succeed there?


Solution

  • is it trying to make the point that

    • Even on architectures with 32-bit signed, nothing guarantees that the effective value +4294967295 is converted to -1?

    ^ This.

    If the type of 0xffffffff is unsigned, as stipulated, then assignment to an object of type [signed] int induces a conversion to that type. The language spec says:

    When a value with integer type is converted to another integer type other than bool, if the value can be represented by the new type, [...]. Otherwise, if the new type is unsigned, [...] 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.

    (C23 6.3.1.3)

    The spec allows for a signal to be raised instead of the conversion proceeding, and if no signal is raised then then the result of the conversion is up to the implementation. The common error Gustedt describes amounts to assuming that the bit pattern of the unsigned value will be reinterpreted as a that of a signed int. Some implementations in fact do that, but they are not required to do, and there are other plausible alternatives. For instance, out of range values might be converted to an extreme value of the destination type.