我没有得到任何目前的答案。C 标准清楚地表明右移负数是实现定义的行为。这不是未指定的行为,这意味着其他东西。正如您正确引用的那样(C17 6.5.7 §5):
E1 >> E2 的结果是 E1 右移 E2 位位置。/--/
如果 E1 具有带符号类型和负值,则结果值是实现定义的。
这意味着编译器必须记录它的行为方式。时期。
在实践中:文档必须说明编译器是使用算术右移还是逻辑右移。
这与未指定行为相反,未指定行为是特定于实现的行为,不需要记录。在两种情况下使用未指定的行为:
- 当编译器行为可能是编译器供应商不应被迫向其竞争对手透露的实现秘密时。
- 当编译器懒得记录底层细节(如 OS 和 RAM 内存单元)如何工作时。
例如,编译器不需要在如下代码中记录评估顺序:
a = f1() + f2();
a += f1() + f2();
记录评估子表达式的顺序将揭示有关编译器内部表达式树和优化器如何工作的详细信息,这反过来将揭示为什么编译器产生更好的代码或编译速度比竞争对手快。在最初编写 C 标准时,这是一件大事。如今,当有一些很棒的开源编译器时,情况就不那么好了,所以它不再是一个秘密。
同样,编译器不需要记录此代码打印的内容:
int a;
int ptr = &a;
printf("%d", *ptr);
a
是一个不确定的值并且输出是未指定的 - 实际上输出取决于之前存储在该特定 RAM 单元中的内容。我们称之为“垃圾价值”。(在大喊“UB”之前,请参阅(Why) is using an uninitialized variable undefined behavior?)。