C 中的操作重新排序和签名

问题描述 投票:0回答:1

我发现了几个讨论有符号和无符号编译器优化的问题。 一般的结论是,由于溢出的未定义行为,signed 允许进行更多优化。 但是,我没有找到任何关于签名如何与操作重新排序一起玩的讨论。

考虑表达式

a - b + c

如果所有值都是无符号的,编译器总是可以重新排序操作(首先添加

a
c
可能会提高性能)。

如果所有值都是有符号的,编译器必须证明重新排序不会导致溢出发生。一般来说,

a + c
可能会溢出,因此编译器在重新排序方面受到限制。

我是否正确认为编译器可以更自由地为无符号值重新排序操作?

c compiler-optimization c99 signed
1个回答
1
投票

如果所有值都是有符号的,编译器必须证明重新排序不会导致溢出发生。

这个前提是错误的。如果 C 程序中没有未定义的行为,编译器的负担就是产生该行为。 C 标准不限制它是如何做到的。如果它重新排序

a - b + c
a + c - b
但是它使用行为适当的指令这样做,那么
a + c - b
将计算与
a - b + c
相同的结果。

考虑使用 32 位

int
对象的示例:
a
是 7FFFFFF016
b
是 10016
c
是 2016。那么
a - b
就是7FFFFEF016
a - b + c
就是7FFFFF1016。如果编译器使用产生 80000010
16
的加法指令计算 a + c,然后使用产生 7FFFFF10
16
的减法指令计算 a + c - b,那么结果是正确的。

这是有效的,因为加法和减法指令不“关心”溢出并产生所需的结果,即使它们超出了

int
范围。不仅这样的指令在当今的处理器上很常见,而且相同的加法和减法指令用于有符号和无符号算术,因为加法和减法的位模式对于无符号和二进制补码表示是相同的。 (比较指令不同,因为当解释为无符号或二进制补码时,这些位具有不同的含义。)

如果源代码字面上被更改为

a + c - b
,程序将具有未定义的行为这一事实是无关紧要的。编译器通常不会通过名义上将 C 源代码重新排列为随后编译的其他 C 源代码来运行。编译器通常通过将 C 语义转换为某种内部表示,然后生成汇编代码来实现这些语义来进行操作。

© www.soinside.com 2019 - 2024. All rights reserved.