相关疑难解决方法(0)

为什么这些构造使用前后增量未定义的行为?

#include <stdio.h>

int main(void)
{
   int i = 0;
   i = i++ + ++i;
   printf("%d\n", i); // 3

   i = 1;
   i = (i++);
   printf("%d\n", i); // 2 Should be 1, no ?

   volatile int u = 0;
   u = u++ + ++u;
   printf("%d\n", u); // 1

   u = 1;
   u = (u++);
   printf("%d\n", u); // 2 Should also be one, no ?

   register int v = 0;
   v = v++ + ++v;
   printf("%d\n", v); // 3 (Should be the …
Run Code Online (Sandbox Code Playgroud)

c increment operator-precedence undefined-behavior sequence-points

793
推荐指数
13
解决办法
7万
查看次数

"x = x ++"之后的x是什么?

执行此操作后会发生什么(窗帘后面)?

int x = 7;
x = x++;
Run Code Online (Sandbox Code Playgroud)

也就是说,当一个变量后期递增并在一个语句中赋值给自己时?我编译并执行了这个.在整个声明之后x仍然是7 .在我的书中,它说增加了!x

java operators post-increment

273
推荐指数
11
解决办法
4万
查看次数

是什么使i = i ++ + 1; 合法的C++ 17?

在开始大喊未定义的行为之前,这在N4659(C++ 17)中明确列出

  i = i++ + 1;        // the value of i is incremented
Run Code Online (Sandbox Code Playgroud)

然而在N3337(C++ 11)

  i = i++ + 1;        // the behavior is undefined
Run Code Online (Sandbox Code Playgroud)

改变了什么?

从我可以收集,从[N4659 basic.exec]

除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的评估是不确定的.[...]在运算符结果的值计算之前,对运算符的操作数的值计算进行排序.如果相对于同一存储器位置上的另一个副作用或者使用同一存储器位置中的任何对象的值进行的值计算,对存储器位置的副作用未被排序,并且它们不可能是并发的,则行为是未定义的.

其中定义为[N4659 basic.type]

对于简单的可复制类型,值表示是对象表示中的一组位,用于确定,该是实现定义的值集的一个离散元素

来自[N3337 basic.exec]

除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的评估是不确定的.[...]在运算符结果的值计算之前,对运算符的操作数的值计算进行排序.如果对标量对象的副作用相对于同一标量对象的另一个副作用或使用相同标量对象的值进行的值计算未被排序,则行为未定义.

同样,值定义在[N3337 basic.type]

对于简单的可复制类型,值表示是对象表示中的一组位,用于确定,该是实现定义的值集的一个离散元素.

它们是相同的,除了提及无关紧要的并发性,并且使用内存位置而不是标量对象,其中

算术类型,枚举类型,指针类型,指向成员类型的指针std::nullptr_t以及这些类型的cv限定版本统称为标量类型.

这不会影响示例.

来自[N4659 expr.ass]

赋值运算符(=)和复合赋值运算符都是从右到左分组.所有都需要一个可修改的左值作为左操作数,并返回一个左值操作数的左值.如果左操作数是位字段,则所有情况下的结果都是位字段.在所有情况下,在右和左操作数的值计算之后,以及在赋值表达式的值计算之前,对赋值进行排序.右操作数在左操作数之前排序.

来自[N3337 expr.ass]

赋值运算符(=)和复合赋值运算符都是从右到左分组.所有都需要一个可修改的左值作为左操作数,并返回一个左值操作数的左值.如果左操作数是位字段,则所有情况下的结果都是位字段.在所有情况下,在右和左操作数的值计算之后,以及在赋值表达式的值计算之前,对赋值进行排序.

唯一的区别是N3337中没有最后一句话.

然而,最后一句话不应该具有任何重要性,因为左操作数i既不是"另一个副作用"也不是 …

c++ language-lawyer c++17

179
推荐指数
3
解决办法
1万
查看次数

重新加载未定义的行为和序列点

将此主题视为以下主题的续篇:

上一部分
未定义的行为和序列点

让我们重新审视这个有趣复杂的表达(斜体短语取自上述主题*smile*):

i += ++i;
Run Code Online (Sandbox Code Playgroud)

我们说这会调用undefined-behavior.我假定说这个的时候,我们隐含假设i是内置的类型之一.

如果什么类型i是用户定义类型?比如它的类型是Index在本文后面定义的(见下文).它还会调用未定义的行为吗?

如果是,为什么?它不等同于写作i.operator+=(i.operator++());甚至语法上更简单 i.add(i.inc());吗?或者,他们是否也调用未定义的行为?

如果不是,为什么不呢?毕竟,对象在连续的序列点之间i被修改两次.请回想一下经验法则:表达式只能在连续的"序列点"之间修改一个对象的值.如果 i += ++i是表达式,那么它必须调用未定义的行为.如果是,那么它的等价物i.operator+=(i.operator++());i.add(i.inc());必须调用undefined-behavior似乎是不真实的!(据我所知)

或者,i += ++i不是一个开头的表达?如果是这样,那么它是什么以及表达式的定义是什么?

如果它是一个表达式,并在同一时间,其行为也是定义良好的,那么就意味着与表达相关序列点的数量在某种程度上取决于该类型的参与表达操作数.我是否正确(甚至部分)?


顺便问一下,这个表达怎么样?

//Consider two cases:
//1. If a is an array of a built-in type
//2. If a is user-defined type which overloads the …
Run Code Online (Sandbox Code Playgroud)

c++ c++-faq undefined-behavior sequence-points

84
推荐指数
5
解决办法
1万
查看次数

这段代码是否定义明确?

此代码取自此处的讨论.

someInstance.Fun(++k).Gun(10).Sun(k).Tun();
Run Code Online (Sandbox Code Playgroud)

这段代码是否定义明确?是否++kkSun()之前评估过Fun ()?

如果k是用户定义的类型,而不是内置类型怎么办?以上函数调用顺序的方式与此不同:

eat(++k);drink(10);sleep(k);
Run Code Online (Sandbox Code Playgroud)

据我所知,在这两种情况下,每个函数调用后都存在一个序列点.如果是这样,为什么第一个案例也不能像第二个案例那样明确定义?

C++ ISO标准的1.9.17部分对序列点和功能评估进行了说明:

在调用函数时(无论函数是否为内联函数),在评估函数体中任何表达式或语句之前发生的所有函数参数(如果有) 之后,都会有 一个序列点.在复制返回值之后和执行函数外部的任何表达式之前,还有一个 序列点.

c++ operator-precedence sequence-points

27
推荐指数
4
解决办法
1758
查看次数