在我阅读的过程中出现了这个问题(答案) 那么为什么i = ++ i + 1在C++ 11中定义明确?
我认为,微妙的解释是(1)表达式++i
返回一个左值但是+
将prvalues作为操作数,因此必须执行从左值到右值的转换; 这涉及获得该左值的当前值(而不是旧值的一个以上i
),因此必须在增量的副作用(即更新)之后进行排序i
(2)赋值的LHS也是左值,所以它的价值评估不涉及取得当前价值i
; 虽然这个值计算在RHS的值计算中是不可测的,但这没有问题.(3)赋值本身的值计算涉及更新i
(再次),但是在其RHS的值计算之后排序,因此在变换之后更新到i
; 没问题.
很好,所以那里没有UB.现在我的问题是如果将分配运算符更改=
为+=
(或类似的运算符).
表达式的评估是否会
i += ++i + 1
导致未定义的行为?
在我看来,标准似乎在这里自相矛盾.由于LHS +=
仍然是左值(并且其RHS仍然是prvalue),所以与上述相同的推理适用于(1)和(2); 在操作数的评估中没有未定义的行为+=
.至于(3),复合赋值的运算+=
(更确切地说是该运算的副作用;它的值计算,如果需要,在任何情况下在其副作用之后排序)现在必须同时获取当前值i
,然后(显然在它之后排序,即使标准没有明确说明,或者对这些运算符的评估总是会调用未定义的行为)添加RHS并将结果存回i
.如果它们的副作用没有排序,这两个操作都会给出未定义的行为++
,但正如上面所论述的那样(在给出运算符的RHS ++
的值计算之前对其进行排序的副作用,该计算值在计算之前排序.该复合转让的操作),情况并非如此.+
+=
但另一方面,标准也表示E += F
相当于E = E + F
,除了(左值)E仅被评估一次.现在在我们的例子中,作为左值的i
(E …
请考虑以下C++标准ISO/IEC 14882:2003(E)引用(第5节,第4段):
除非另有说明,否则单个运算符的操作数和单个表达式的子表达式的评估顺序以及副作用发生的顺序是未指定的.53)在前一个和下一个序列点之间,标量对象应通过表达式的计算最多修改其存储值一次.此外,只能访问先前值以确定要存储的值.对于完整表达式的子表达式的每个允许排序,应满足本段的要求; 否则行为未定义.[例:
Run Code Online (Sandbox Code Playgroud)i = v[i++]; // the behavior is unspecified i = 7, i++, i++; // i becomes 9 i = ++i + 1; // the behavior is unspecified i = i + 1; // the value of i is incremented
- 末端的例子]
我很惊讶,i = ++i + 1
给出了一个未定义的值i
.有没有人知道编译器实现不能给出2
以下情况?
int i = 0;
i = ++i + 1;
std::cout << i << std::endl;
Run Code Online (Sandbox Code Playgroud)
事情是operator=
有两个args.第一个总是i
参考.在这种情况下,评估顺序无关紧要.除了C++ Standard禁忌之外,我没有看到任何问题.
请,不要不考虑这样的情况下,参数的顺序是评价非常重要.例如, …
我已经开始研究C++ 0x了.我偶然发现了以下表达方式:
int l = 1, m=2;
++l *= m;
Run Code Online (Sandbox Code Playgroud)
我不知道第二个表达式是否有明确定义的行为.所以我在这里问.
不是UB吗?我只是渴望知道.
在下面的代码中摘录了一段较大的代码
void func(int* usedNum, int wher) {
*usedNum = *usedNum + 1 > wher ? ++(*usedNum) : wher + 1;
}
int main(void) {
int a = 11, b = 2;
func(&a, b);
}
Run Code Online (Sandbox Code Playgroud)
一个警告发出
warning: operation on '* usedNum' may be undefined [-Wsequence-point]
*usedNum = *usedNum + 1 > wher ? ++(*usedNum) : wher + 1;
Run Code Online (Sandbox Code Playgroud)
代码有问题吗?
我怀疑的是这个以及它所说的部分
序列指向逻辑表达式,例如&&和|| 和三元运算符?:和逗号运算符表示在右侧操作数之前计算左侧操作数.这几个操作数是C++中唯一引入序列点的操作数.
对于那些发现折磨阅读评论的人:最初的问题没有恰当地提出,造成误解是不公平的.我对这个主题的看法有两个方面
三元运算符不会(以意想不到的方式)混乱序列点(其中,两个分支在C,C++的每个版本中排序 - 请参阅提供的链接)
是x = ++x
问题吗?如coliru链接所示,我们编译为c ++ 14.那里的操作定义很好(对注释的引用),但旧版本的c ++和c将其视为未定义.那为什么会有警告? …
我知道这看起来很熟悉但是在微软招募实习生的测试中,这是一个问题.在我看来,这y=++y
不符合标准,但我认为可能更好(确定我比那些在MS上编写这些测试的人更好).所以我问你的建议.您认为这样的表达式是否符合标准并且不会导致未定义的行为?
#include <stdio.h>
int main(){
int a = 10;
int b = 10;
a = ++a; //What ???
b = b++; //What ???
printf("%d %d\n",a,b);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
gcc
用来编译时抱怨它-Wsequence-point
.(没有明确说明它是否是C或C++特定问题.)
但只提供了四个答案:
a) 10 10
b) 11 10
c) 10 11
d) 11 11
Run Code Online (Sandbox Code Playgroud)
虽然一个人不仅限于选择一个答案(所以也许我应该选择全部四个?)
嗯,在我看来,在自我递增和分配之间没有序列点.所以这违反了规范.不是吗?
随着新的大学一年到来.
我们已经开始接收标准为什么++ i ++
不能按预期问题工作.
在回答了这些类型的问题之一后,我被告知新的C++ 11标准已经改变,这不再是未定义的行为.我听说sequence points
已经被这个主题所取代sequenced before
,sequenced after
但没有深入阅读(或根本没有).
所以我刚回答的问题是:
int i = 12;
k = ++ (++ i);
Run Code Online (Sandbox Code Playgroud)
所以问题是:
如何在C++ 11中改变序列点,以及它如何影响上述问题.它仍然是未定义的行为还是现在定义得很好?
在C++ 11 3p3中,它指出:
实体是值,对象,引用,函数,枚举器,类型,类成员,模板,模板特化,命名空间,参数包或此.
在17.6.1.1p1中,它指出:
C++标准库提供以下类型实体的定义:宏,值,类型,模板,类,函数,对象.
什么是C++标准库为(不是对象?)和对话提供定义的值的示例:C++标准库为其定义的对象的示例是什么,不是值?
我有这行代码:
front = (++front) % size;
Run Code Online (Sandbox Code Playgroud)
在CI中没有警告但在C++中我收到警告operation on front may be undefined [-Wsequence-point]
.这个preincrement用法如何导致未定义的行为?在我看来,这条线非常明确,将被解释为:
我的编译器只是抛出一个警告吗?
PS我理解警告,如果我做的事情front = front++;
或天堂禁止front = front++ + front++;
.
编辑:此警告是在Windows 64上的CodeBlocks中使用GCC(tdm-1)4.6.1生成的
我的一些同事今天进行了辩论,我想澄清一下.它是关于表达式中的评估顺序和序列点.标准中明确指出,C/C++在表达式中没有从左到右的评估,这与Java之类的语言不同,后者保证具有从左到右的顺序.因此,在下面的表达式中,在评估最右边的操作数(C)之前,对二进制操作中最左边的操作数(B)的求值进行排序:
A = B B_OP C
Run Code Online (Sandbox Code Playgroud)
根据序列前序列(Undefined Behavior)和Bjarne的TCPPL 3rd ed 下的CPPReference,下面的表达式是UB
x = x++ + 1;
Run Code Online (Sandbox Code Playgroud)
它可以被解释为像BUT这样的编译器,据说下面的表达式在C++ 11中显然是一个明确定义的行为
x = ++x + 1;
Run Code Online (Sandbox Code Playgroud)
那么,如果上面的表达式定义得很清楚,那么"命运"是什么呢?
array[x] = ++x;
Run Code Online (Sandbox Code Playgroud)
似乎没有定义后增量和后减量的评估,但定义了预增量和预减量.
注意:这不用于实际代码中.Clang 3.4和GCC 4.8明确警告了增量前后序列点.