可能不一致的铸造行为

Ioa*_*oan 5 c gcc mingw-w64

GCC 4.8.0编译/为32位.

我发现案例2和案例6的行为令人困惑:

int16_t s16 = 0;
double dbl = 0.0;

s16 = (int16_t)((double)32767.0); // 1: s16 = 32767
s16 = (int16_t)((double)32768.0); // 2: s16 = 32767
s16 = (int16_t)((double)-32768.0); // 3: s16 = -32768
s16 = (int16_t)((double)-32769.0); // 4: s16 = -32768

dbl = 32767.0;
s16 = (int16_t)dbl; // 5: s16 = 32767
dbl = 32768.0;
s16 = (int16_t)dbl; // 6: s16 = -32768  
dbl = -32768.0;
s16 = (int16_t)dbl; // 7: s16 = -32768
dbl = -32769.0;
s16 = (int16_t)dbl; // 8: s16 = -32768
Run Code Online (Sandbox Code Playgroud)

我意识到它的实现是定义的,但一致性仍然很好.谁能解释一下发生了什么?

Dan*_*her 3

根据 6.3.1.4 (1),该行为不是实现定义的,而是未定义的:

\n
\n

如果整数部分的值不能用整数类型表示,则行为未定义。61)

\n

61)当实数浮点类型的值转换为无符号类型时,不需要执行整数类型的值转换为无符号类型时执行的余数运算。因此,可移植实浮点值的范围是(\xe2\x88\x921, Utype_MAX+1)

\n
\n

该段落在 C99 中是相同的,只是脚注的编号不同 (50)。

\n

对于未定义的行为,编译时求值的表达式的行为与运行时求值的行为不同并不罕见,例如

\n
1 << width_of_type\n
Run Code Online (Sandbox Code Playgroud)\n

如果移动距离作为常量表达式给出,则通常评估为 0;如果是运行时值,则通常评估为 1。

\n

据我所知,导致同一代码出现不同行为的原因是,由于未定义的行为是编译器生成任何内容的许可证,因此它也可能会做最简单和/或最快的事情,以及最简单的事情编译期间/最快的事情可能与运行时最简单/最快的事情不同。

\n

  • 可以理解,但事实并非如此。如果我使用优化进行编译,则后四个结果与前四个结果相同,因此相同的代码的行为会有所不同,具体取决于优化级别。据我所知,其推理是“如果行为未定义,只需利用它并做最快/最简单的事情”。 (2认同)