1

我正在尝试为左移负数时未定义的行为生成警告。根据这个答案,C中负数的左移是未定义的。

E1 << E2 的结果是 E1 左移 E2 位位置;空出的位用零填充。如果 E1 具有无符号类型,则结果的值为 E1×2E2,比结果类型中可表示的最大值多模一减少。如果 E1 有带符号类型和非负值,并且 E1×2E2 在结果类型中是可表示的,那么这就是结果值;否则,行为未定义。

我试图了解为什么我没有收到此代码的警告: x << 3

gcc -Wall(版本 9.1.0)

int main ()
{
    int x= -4, y, z=5;
    y = z << x;
    y = x << 3;
    return y;
}

另外,我也没有收到关于左移负数的警告 z << x

4

3 回答 3

1

5 << -4GCC 9.1.0 和带有 clang-1001.0.46.4 的 Apple LLVM 10.0.1 中,针对 x86-64,发出警告消息(GCC 的“左移计数为负”,LLVM-clang 的“移位计数为负” )。在-4 << 3中,GCC 不会发出警告,但 LLVM-clang 会发出警告(“移动负值是未定义的”)。

在这两种情况下,C 标准都不需要诊断,因此编译器是否需要诊断是实现的质量问题(或者,编译器可能通过定义负值的左移来扩展 C,因此不考虑它一个错误)。

当操作数不是常量时,例如z << xand x << 3,我们可能会推测编译器无法看到操作数是否为负数,因此它不会发出警告。通常,这些表达式可能具有已定义的行为:如果x不是负数并且在适当的范围内(不大于z前一种情况的宽度,并且在后一种情况下不会大到x << 3溢出),则行为已定义(除了z << x可能溢出的可能性)。C 标准并没有说带有可能具有负值的类型(有符号类型)的左移是未定义的,只是带有负值的左移是未定义的。因此,编译器在任何时候发出警告消息都是错误的x是表达式中的有符号类型,例如z << xor x << 3

当然,鉴于初始化和表达式and之间int x = -4没有任何更改,编译器可以推断出在这种特定情况下未定义移位并发出警告。这不是标准所要求的,编译器未能这样做只是编译器实现质量的问题。xz << xx << 3

于 2019-06-29T22:52:25.840 回答
1

在这种情况下编译器不发出警告的简短解释是因为它不是必需的。

标准中“未定义”的定义也明确指出“不需要诊断”。这意味着该标准不需要实现来在这种情况下发出诊断。其原因是,从技术上讲,编译器可能无法在合理的时间内或(在某些情况下)根本无法检测到所有未定义行为的实例。有些情况只能在运行时检测到。编译器是复杂的代码片段,因此即使人类可以轻松识别问题,编译器也可能无法识别(另一方面,编译器也会检测人类无法轻易发现的问题)。

当不需要诊断时,在编译器发出警告之前,有几件事必须发生 - 所有这些都是自行决定的。

发生的第一件事就是“实现质量”问题——供应商或编译器开发人员选择编写检测特定情况的代码和其他发出警告的代码

这两个步骤(检测一个案例,并发出警告)是独立的,完全可以自行决定——标准不需要诊断,因此,即使编写了检测特定案例的代码,编译器仍然不需要发出关于它。实际上,即使检测到问题,编译器开发人员也可能出于各种原因选择不发出警告。一些警告是关于罕见的边缘情况,因此不值得努力发出它们。一些警告具有固有的“误报”率,这往往会导致开发人员在向编译器供应商的错误报告中抱怨不必要的警告 - 因此编译器默认配置为不发出它们。

发出警告的下一个要求是编译器的用户必须选择显示警告。由于开发人员对供应商的大力游说——大多数现代编译器都是默认配置的,因此它们只发出相对少量的警告。因此,希望尽可能多地从编译器获得帮助的开发人员需要显式启用它。例如,通过使用-Wallgcc 和 clang 的选项。

于 2019-06-30T02:58:28.490 回答
0

在 C89 中为左操作数的所有整数值指定了将任何值左移小于字长的量的行为,即使负左操作数的指定行为在非 2 上通常不太理想 -补码平台,或者在错误捕获平台上,如果迭代乘以 2 会溢出。

为了避免要求实现以不太理想的方式运行,C99 的作者决定允许实现以他们认为合适的方式处理此类情况。C99 标准的作者并没有试图猜测实现可能有充分理由偏离 C89 行为的所有地方,而是推测实现将遵循 C89 行为,而没有充分的理由不这样做,标准是否强制他们这样做与否。

如果标准的作者打算在 C89 行为有意义的情况下对左移操作的处理进行任何更改,应该在已发布的基本原理文档中提及更改。什么都没有。我可以从这种遗漏中看到的唯一推论是,从“以几乎总是有意义的特定方式行事”到“如果实施者判断它有意义,则以这种方式行事,否则以任何其他方式处理代码实施者认为合适的时尚”没有被视为足以证明评论合理的变化。标准的作者没有强制执行某种行为这一事实绝不意味着他们没有预料到通用的二进制补码实现不会像往常一样继续处理这种转变,程序员也不应该有权获得类似的期望。

于 2019-06-29T21:06:45.103 回答