Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jsp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么if语句中未定义的behavoir为true?_C_Undefined Behavior - Fatal编程技术网

C 为什么if语句中未定义的behavoir为true?

C 为什么if语句中未定义的behavoir为true?,c,undefined-behavior,C,Undefined Behavior,在这个程序中有一个未定义的行为。输出总是true。我试过几个编译器。有人能解释一下为什么它总是true吗?是的,代码将始终返回true,因为任何条件语句中的任何非零值都是true(上面的C-99)或1(C-99) 在if条件中,2首先分配给y,然后2与2按位&'。 i、 e.0010和0010结果将返回0010 现在你有了: if (y & (y = 2)) printf("true %d\n"); 您试图在序列点之间多次修改y的值。对于如何处理这种行为,没有一个标准的方法。因

在这个程序中有一个未定义的行为。输出总是
true
。我试过几个编译器。有人能解释一下为什么它总是
true
吗?

是的,代码将始终返回
true
,因为任何条件语句中的任何非零值都是
true
(上面的C-99)或
1
(C-99)

在if条件中,2首先分配给y,然后2与2按位&'。 i、 e.0010和0010结果将返回0010

现在你有了:

if (y & (y = 2))
    printf("true %d\n");

您试图在序列点之间多次修改y的值。对于如何处理这种行为,没有一个标准的方法。因此:

if(2)  //Any non-zero value is true
    printf("true %d\n");

瓦尔特

因为观察到的行为没有定义。您正在使用的编译器(仅通过观察)似乎正在执行以下操作:

  • 分配
    y=2
  • 步骤(1)的评估结果
  • 评估
    y
  • 按位与上面步骤(2)和(3)的结果
  • 步骤(4)的评估结果
  • 结果将是
    (2和2)
    ,这是正确的。问题是,1-2,然后3的顺序不是标准定义的。也可能是这样的:

  • 评估
    y
  • 分配
    y=2
  • 步骤(2)的评估结果
  • 按位与上面步骤(1)和(3)的结果
  • 步骤(4)的评估结果
  • 结果将是
    (1和2)
    ,即false

    或者完全是别的什么东西。并不是所有的编译器都会做第一件事,你不能假设,因为你使用的编译器都会做第一件事。你也不能假设,因为他们这样做了,而且你观察到了这种行为,所以它就被定义了;事实并非如此编译器不定义行为;标准是这样的,编译器有义务遵守。

    注:这个定义时代有一个漏洞,但它不是规范,甚至标准对它的定义也很松散。你会发现标准中的一些地方,比如“实现定义”。在这种情况下,标准会合理清晰地指出这些分歧的地方。在这种情况下,您应该咨询您的实现以获得关于预期行为的最终结论,并且在这样做的过程中,准备接受一个简单的事实,即这种行为只能在实现的范围内被依赖。这(你的样品)不是这样的漏洞例外

    根据我的观察,我的Clang3.5装备似乎运行第二个序列,而不是第一个序列,我可以按照你的方式假设我尝试过的“所有”编译器(其中一个)都是这样运行的,因此它被定义为这样。我这样做是错误的,正如你所设想的那样


    未定义的行为就是这样;未定义。

    您使用的是按位and&,使用&&表示普通的“and”运算符,如果要检查其是否为2,则y==2。此外,由于您没有传递printf任何内容,因此该代码将无法工作。非常确定的是,(0x01&0x02)为false,但他尝试的所有编译器似乎都会首先计算括号赋值,从而导致(0x02&0x02),这是真的。正如下面的答案似乎得出的结论,我很确定这项任务不是偶然的。(在有人问之前,我没有投任何人的反对票)@PankajMahato在clang 3.5-O3上编译这个,我收到的是假的,所以可能会改变一下你的测试平台。另外,她也很聪明,给了我这个,我猜你已经知道了:
    警告:未排序的修改和访问“y”[-Wunsequenced]
    真的没有“为什么”这个问题“在这儿。未定义的行为是未定义的;无法保证它会返回真值。正如提问者所说,行为是未定义的。对两个操作数的求值不存在排序。如果您花时间阅读注释,您会发现它并非总是正确的。即使是这样,这也绝对不会影响行为是否未定义。在LLVM版本5编译器上,get false带有警告。警告:未排序的修改和对“y”@SaurabhSharma的访问:从“在我使用多个编译器测试的每个特定实例中,这都是正确的”推断“这一直是正确的”是无效的。得出“始终如此”(其中“始终”是“每个标准C实现”)结论的唯一方法是从C标准中为C指定的规则中推断出来。标准C的规则很明确:如果您都使用一个对象(
    y
    ),并分别修改它(
    y=2
    )在一个表达式中,如果没有对其求值进行排序,则该行为是未定义的。您的第二段简要介绍了所讨论的未定义行为。您假设了该序列,而他尝试执行的编译器似乎就是这样。但是,在您注意到的位置上没有定义的序列点,因此是这样的UB.这个答案中的其他所有内容都解释了为什么结果是真的。这很容易是目前为止最好的答案,如果这个答案只是说“因为你正在使用的编译器似乎可以做到这一点:废话,但它们不是必需的,有些则不是”我会很快对此进行投票。我不想再拖下去了,但可能值得注意的是,编译器可能会检测到表达式
    (y&(y=2))
    未定义(因此既不是真的也不是假的),并优化整个过程。该程序可能根本不会打印任何内容。@StephenCanon这是一个完全公平的观点,值得进行评论投票。或者它可能会决定所有UB评估在我的小“I-get-to-define-what-UB-is-universe”中都是错误的。很好的一点。UB,你是一个残忍无情的婊子。
    if (y & (y = 2))
        printf("true %d\n");
    
    if(2)  //Any non-zero value is true
        printf("true %d\n");
    
    i = i++; // gives undefined behavior also