代码之家  ›  专栏  ›  技术社区  ›  msc

是“-1>>5;”C中未指定的行为?

  •  39
  • msc  · 技术社区  · 8 年前

    结果 E1 >> E2 E1 右移 E2 位位置。如果 具有无符号类型或如果 E1 具有签名类型和 非负值,结果的值是 E1 / 2*^E2 . E1 有符号类型和负数

    但是 viva64 参考文件规定:

    int B;
    B = -1 >> 5; // unspecified behavior
    

    我在上运行了此代码 GCC 它总是给出一个输出 -1

    那么,标准就是这样 “如果E1有符号类型和负值,则结果值由实现定义” 但文件上说 -1>>5; 未指定行为

    那么 -1>&燃气轮机;5. C中未指定的行为?哪个是正确的?

    4 回复  |  直到 7 年前
        1
  •  39
  •   dbush    8 年前

    引用第3.4.1节 the C standard 定义了“实现定义的行为”:

    1. 实现定义的行为

    未指定的行为,其中每个实现记录了如何做出选择

    2. 示例实现定义的行为示例是高阶位的传播

    根据第3.4.4节定义“未指定行为”:

    未指定行为

    国际标准提供了两种或两种以上的可能性和强制要求 在任何情况下都没有选择进一步的要求

    2. 示例未指定行为的示例是函数参数的求值顺序。

    GCC documentation :

    位运算符作用于值的表示,包括 符号位和值位,其中考虑符号位 在最高值位的正上方。 >> 符号扩展的负数。

    作为C语言的扩展,GCC不使用给定的纬度 在C99和C11中,仅处理签名的某些方面 << 像 未定义。然而 -fsanitize=shift (和 -fsanitize=undefined )威尔 诊断此类病例。他们还被诊断为常数 表达式是必需的。

        2
  •  14
  •   skrrgwasme    8 年前

    “未指定行为”和“实现定义”并不矛盾。这只是意味着C标准没有规定需要做什么,各种实现可以做他们认为“正确”的事情

    那个特定的编译器 是一致的。在不同的编译器上可能会得到不同的结果。

        3
  •  2
  •   Antti Haapala -- Слава Україні    7 年前

    实现定义的行为是 子类 未指定行为,即标准未规定的行为。

    缺陷报告#154至C89询问委员会 implementation-defined behaviour ; 委员会回答说,实施可以定义它想要的任何行为,而不需要是恒定的。

    实现需要做的是记录 怎样 这种选择是做出的,而不是另一类未指定的行为,在这种行为中,一致性实现甚至不需要费心说明 怎样 作出选择,可能是因为对于这些实现,文本中的大多数会说“随机”或“取决于编译器优化级别”或“取决于局部变量的寄存器分配”。

        4
  •  2
  •   Lundin    7 年前

    我现在没有得到任何答案。C标准明确指出,右移负数是 实现定义的行为 . 它是

    E1的结果>&燃气轮机;E2是E1右移的E2位位置/--/
    如果E1具有有符号类型和负值,则结果值由实现定义。

    记录其行为。时期

    在实践中:文档必须告诉编译器是使用算术右移还是逻辑右移。


    没有 需要记录。未指定的行为用于两种情况:

    • 当编译器行为可能是编译器供应商不应被迫向其竞争对手透露的实现秘密时。

    例如,编译器不需要在这样的代码中记录求值顺序:

    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?

    推荐文章