int16_t到int会话可以导致实现定义的行为吗?

Vil*_*ray 12 c casting c99 type-conversion language-lawyer

在C99标准的第7.18.1.1节第1段中:

typedef名称intN_t指定有符号整数类型,其宽度为N,无填充位和二进制补码表示.

根据C99标准,精确宽度有符号整数类型需要具有二进制补码表示.这意味着,例如,int8_t具有最小值-128而不是1的补码最小值-127.

第6.2.6.2节第2段允许实现决定是将符号位解释为符号和幅度,二进制补码还是一个补码:

如果符号位为1,则应以下列方式之一修改该值:
- 符号位0的相应值被否定(符号和幅度);
- 符号位的值为 - (2 N)(二进制补码);
- 符号位的值为 - (2 N - 1)(1'补码).

方法之间的不同之处很重要,因为二进制补码(-128)中的整数的最小值可能超出了补码(-127to 127)中可表示的值的范围.

假设一个实现将int类型定义为具有ones' complement表示,而int16_t类型具有two's complementC99标准保证的表示.

int16_t foo = -32768;
int bar = foo;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,转换int16_t是否int会导致实现定义的行为,因为持有的值foo超出了可表示的值范围bar

Kei*_*son 8

是.

具体而言,转换将产生实现定义的结果.(对于除了之外的任何值-32768,结果和行为将被很好地定义.)或者转换可以引发实现定义的信号,但我不知道任何实现这样做.

参考转换规则:N1570 6.3.1.3p3:

否则,新类型将被签名,并且值无法在其中表示; 结果是实现定义的,或者引发实现定义的信号.

只有在以下情况下才会发生

  • int 是16位(更准确地说,有15个值位,1个符号位,0个或更多填充位)
  • int 使用一个补数或符号和幅度
  • 该实现还支持二进制补码(否则它将不会定义int16_t).

看到满足这些标准的实现,我会感到惊讶.它必须支持二进制补码和一个补码或符号和数量,并且它必须选择后者中的一个用于类型int.(也许非二进制补码实现可能支持软件中的二进制补码,只是为了能够定义int16_t.)

如果您担心这种可能性,可以考虑将其添加到您的一个头文件中:

#include <limits.h>
#include <stdint.h>

#if !defined(INT16_MIN)
#error "int16_t is not defined"
#elif INT_MIN > INT16_MIN
#error "Sorry, I just can't cope with this weird implementation"
#endif
Run Code Online (Sandbox Code Playgroud)

#errors为可能不会触发任何理智的现实世界中的实现.

  • @VilhelmGray:使用`#error`(a)尽早捕获错误,(b)让我控制出现的错误消息,(c)保证代码实际上无法编译.语法错误和约束违规的诊断只是警告,编译仍在继续(语言扩展可以这种方式实现); 只有`#error`才能保证失败. (2认同)