【问题标题】:Is this undefined behavior in C/C++这是 C/C++ 中未定义的行为吗
【发布时间】:2011-03-22 09:53:57
【问题描述】:
int foo(int c){
    return c;
}

int main(void){
    int a=5,c;
    c = foo(--a) + a; 
}

它会在 C/C++ 中调用未定义的行为吗?我认为不会。

阅读所有答案后,我无法弄清楚这是未定义的行为还是未指定的行为。

【问题讨论】:

  • 不,它不会,因为它不会编译。 (分号在哪里!)
  • stackoverflow.com/questions/4176328/… 有很多关于这方面的信息。
  • 除非你实现了一个编译器,或者一个编译器测试套件,或者你的公司雇佣了一群语言律师,否则我会怀疑你是否需要知道这一点。是的,SO 上有几个人可以回答这个问题(你可以在 Usenet 上的 comp.lang.c++.moderatedcomp.std.c++ 上找到更多信息),但人数并不多,甚至他们有时也会对微妙的极端情况持不同意见。更重要的是,(某些)编译器也可能不同意它们。如果代码不够清晰,看一眼,一个经验丰富的程序员可能会说“是的!”或“不!”,简化它并完成。
  • 我回答错了来证明一个观点:)
  • @Matt:你的回答让我吃惊!让我跳入我的 FCD 副本以检查我是否没有跳过某些内容! @Erik 正在报道我们 :)

标签: c++ c undefined-behavior


【解决方案1】:

是的,这是未定义的行为 - afoo(--a) 可以按任何顺序进行评估。

如需进一步参考,请参阅例如Sequence Point。在完整的表达式之后有一个序列点,在对foo 的参数求值之后 - 但子表达式的求值顺序未指定,每 5/4:

除非另有说明,否则顺序 个人操作数的评估 的运算符和子表达式 个别表达和顺序 发生副作用的地方,是 未指定。上一个之间 下一个序列指向一个标量 对象应该有它的存储值 最多修改一次 表达式的评估。 此外,先验值应为 仅访问以确定值 要存储。这个要求 段应满足每个 允许的排序 完整表达式的子表达式; 否则行为未定义。

编辑:正如 Prasoon 指出的那样,由于 评估的顺序......未指定,因此行为是 未指定的。,并变为 未定义 由于只能访问先验值以确定要存储的值

【讨论】:

  • 据我了解,情况更糟。没有什么能阻止a--a 之后但在foo(...) 之前被评估,如果foo 进一步改变a 的值,这可能很重要。
  • @Eric :这不是唯一的原因。例如,int c = foo(k--) + foo(--j) 不会调用 undefiend 行为,即使 + 的评估顺序未指定。
  • @Eric :行为不仅未指定,而且也未定义。阅读我的答案。 :)
【解决方案2】:

你应该阅读this,它会告诉你你的代码是未定义的,因为+不是一个序列点,因此它是未定义是先评估f(--a)还是a

【讨论】:

  • 或阅读 Prasoon 的优秀 FAQ entry 关于此事。
【解决方案3】:

即使+ 运算符的操作数可以按任一顺序求值,但行为未定义,因为它违反了第二条规则

1) 在前一个序列点和下一个序列点之间,对象的存储值最多只能通过表达式的评估修改一次。

2) 此外,只能访问先验值以确定要存储的值

以下定义明确

c = foo(a-1) + a ;

阅读this FAQ entry 以更好地了解未定义的行为和序列点。

【讨论】:

    【解决方案4】:

    根据Wikipedia +不是一个序列点,所以评估的顺序是不固定的,因此你有未定义的行为。

    【讨论】:

    • 使用 evaluation 代替 execution
    【解决方案5】:

    您将在 main 函数中收到有关返回类型的警告,否则在 main() 结束时正常且 c = 8。

    【讨论】:

    • ...不,你不会也不一定。
    • 是的,我同意不一定。我的意思是“你可能会得到”
    • -1 - 这是不正确的 - 阅读序列点:en.wikipedia.org/wiki/Sequence_point
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-20
    • 1970-01-01
    • 2019-05-21
    相关资源
    最近更新 更多