是“*p = ++(*q)”吗?当 p 和 q 指向同一个对象时未定义?

发布于 2024-09-16 15:15:20 字数 347 浏览 2 评论 0原文

在阅读了有关序列点的内容后,我了解到 i = ++i 是未定义的。

那么这段代码怎么样:

int i;
int *p = &i;
int *q = &i;
 *p = ++(*q);           // that should also be undefined right?

假设 p 和 q 的初始化是否取决于某些(复杂的)条件。 它们可能指向同一个对象,就像上面的例子一样。 会发生什么?如果未定义,我们可以使用什么工具来检测?

编辑:如果两个指针不应该指向同一个对象,我们可以使用 C99 限制吗? 这就是‘严格’的意思吗?

after reading about sequence points, I learned that i = ++i is undefined.

So how about this code:

int i;
int *p = &i;
int *q = &i;
 *p = ++(*q);           // that should also be undefined right?

Let's say if initialization of p and q depends on some (complicated) condition.
And they may be pointing to same object like in above case.
What will happen? If it is undefined, what tools can we use to detect?

Edit: If two pointers are not supposed to point to same object, can we use C99 restrict?
Is it what 'strict' mean?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

猫腻 2024-09-23 15:15:20

是的,这是未定义的行为——您对一个对象进行了两次修改,而它们之间没有序列点。不幸的是,自动检查这一点非常困难——我能想到的最好的办法就是在这之前添加assert(p != q),这至少会给出一个干净的运行时错误,而不是更糟糕的情况。在一般情况下,在编译时检查这一点是不可判定的。

Yes, this is undefined behavior -- you have two modifications of an object without a sequence point between them. Unfortunately, checking for this automatically is very hard -- the best I can think of is adding assert(p != q) right before this, which will at least give a clean runtime fault rather than something worse. Checking this at compile time is undecidable in the general case.

陌路终见情 2024-09-23 15:15:20

最好的工具不是检测,而是首先避免这种情况,那就是使用良好的编程实践。避免副作用,并且每个作业的写入次数不超过一次。没有什么问题

*q += 1;
*p = *q;

The best tool not to detect, but to avoid this in the first place is to use good programming practice. Avoid side-effects and do no more than one write per assignment. There is nothing wrong with

*q += 1;
*p = *q;
俏︾媚 2024-09-23 15:15:20

表达式与 i=++i 相同。唯一可以检测到它的工具是你的头。在 C 语言中,权力伴随着责任。

The expression is the same as i=++i. The only tool that can detect it is your head. In C with power comes responsibility.

她说她爱他 2024-09-23 15:15:20

第 5 章表达式

第 4 点:

除非另有说明,否则各个运算符的操作数和各个表达式的子表达式的求值顺序以及副作用发生的顺序均未指定。 在上一个和下一个序列点之间,标量对象的存储值最多应通过表达式的求值修改一次。此外,应仅访问先前值以确定要存储的值。对于完整表达式的子表达式的每个允许的排序,应满足本段的要求;否则行为未定义。

[ Example:
  i = v[i ++];           / / the behavior is undefined
  i = 7 , i++ , i ++;    / / i becomes 9
  i = ++ i + 1;          / / the behavior is undefined 
  i = i + 1;             / / the value of i is incremented
—end example ]

因此,这是未定义的行为:

int i;
int *p = &i;
int *q = &i;
*p = ++(*q);   // Bad Line

在“Bad Line”中,标量对象“i”在表达式求值期间多次更新。仅仅因为对象“i”被间接访问并不会改变规则。

Chapter 5 Expressions

Point 4:

Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified. Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.

[ Example:
  i = v[i ++];           / / the behavior is undefined
  i = 7 , i++ , i ++;    / / i becomes 9
  i = ++ i + 1;          / / the behavior is undefined 
  i = i + 1;             / / the value of i is incremented
—end example ]

As a result this is undefined behavior:

int i;
int *p = &i;
int *q = &i;
*p = ++(*q);   // Bad Line

In 'Bad Line' the scalar object 'i' is update more than once during the evaluation of the expression. Just because the object 'i' is accessed indirectly does not change the rule.

好久不见√ 2024-09-23 15:15:20

这是个好问题。您强调的一件事是“序列点”,引用自此 site< /a>

为什么你不能依赖以下表达式:
a[i] = i++;
因为没有为赋值、增量或索引运算符指定序列点,所以您不知道增量对 i 的影响何时发生。

更进一步,上面的表达式类似地相同,所以行为是未定义,至于追踪它的工具,为零,当然有splint 举个例子,但它是一个 C 标准,所以也许在我还没有听说过的工具中存在一个隐藏选项,也许 Gimpel 的 PC Lint 或 Riverblade 的 Visual lint 可能会对您有所帮助,尽管我承认它没有提及任何有关跟踪这方面未定义行为的内容。

顺便说一句,GCC 的编译器版本 4.3.3 有这个选项 -Wsequence-point 作为标记警告的一部分。这在我的 Slackware 13.0 盒子上...

它只是表明,该代码可能看起来没问题肉眼可以编译得很好,但以后可能会引起头痛,最好的方法是进行代码审查,可以发现编译器可能无法识别的东西,这是最好的选择武器!

That's a good question. The one thing you have highlighted is 'sequence points', to quote from this site

why you cannot rely on expressions such as:
a[i] = i++;
because there is no sequence point specified for the assignment, increment or index operators, you don't know when the effect of the increment on i occurs.

And further more, that expression above is similarly the same, so the behaviour is undefined, as for tools to track that down, is zero, sure there's splint to name one as an example, but it's a C standard, so maybe there's a hidden option in a tool that I have not yet heard of, maybe Gimpel's PC Lint or Riverblade's Visual lint might help you although I'll admit it does not mention anything about tracking down undefined behaviour in this regard.

Incidentally, GCC's compiler version 4.3.3 has this option -Wsequence-point as part of flagging up warnings..this is on my Slackware 13.0 box...

It just shows, that code may look ok to the naked eye and will compile just fine, but can cause headaches later on, the best way to do it is to have code review that can spot out things a compiler may not pick up on, that is the best weapon of choice!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文