标准中的哪种语言使此代码可以工作并打印“-1”?
\nunsigned int u = UINT_MAX;\nsigned int s = u;\nprintf("%d", s);\nRun Code Online (Sandbox Code Playgroud)\nhttps://en.cppreference.com/w/c/language/conversion
\n\n\n否则,如果目标类型已签名,则行为是实现定义的(可能包括引发信号)
\n
https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation
\n\n\n\n
\n- \n
GCC仅支持两个\xe2\x80\x99s补码整数类型,并且所有位模式都是普通值。
\n- \n
当值无法在该类型的对象中表示时,将整数转换为有符号整数类型的结果或引发的信号(C90 6.2.1.2、C99 和 C11 6.3.1.3):
\n为了转换为宽度为 N 的类型,该值会以 2^N 为模减少到该类型的范围内;没有发出任何信号。
\n
对我来说,转换UINT_MAX为 anint似乎意味着UINT_MAX除以2^(CHAR_BIT * sizeof(int))。为了便于讨论,对于 32 位整数,0xFFFFFFFF / 2^32 = 0xFFFFFFFF. 所以这并不能真正解释值“-1”如何最终出现在int.
在其他地方是否有某种语言说在模除法之后我们只是重新解释这些位?或者标准的其他部分优先于我引用的部分?
\nC 标准的任何部分都不能保证您的代码通常会打印 -1。正如它所说,转换的结果是实现定义的。然而,GCC 文档确实承诺,如果您使用它们的实现进行编译,那么您的代码将打印 -1。这与位模式无关,只是数学。
GCC 手册中对“约简模 2^N”的明确解读是,结果应该是与signed int输入一致的模 2^N 范围内的唯一数字。这是定义您期望的“包装”行为的精确数学方法,它恰好与您通过重新解释这些位得到的结果一致。
假设为 32 位,UINT_MAX则值为 4294967295。这与 4294967296 模到 -1 一致。也就是说,4294967295和-1之间的差是4294967296的倍数,即4294967296本身。此外,这必然是[-2147483648, 2147483647]中唯一的此类数字。(与 -1 全等的任何其他数字将至少为-1 + 4294967296 = 4294967295,或最多为-1 - 4294967296 = -4294967297)。所以-1就是转换的结果。
换句话说,重复加或减 4294967296,直到得到 范围内的数字signed int。保证只有一个这样的数字,在本例中为 -1。