C++ 未定义的行为和序列点
什么是“序列点” 未定义的行为和序列点之间的关系是什么 我经常使用有趣而复杂的表达式,比如C++ 未定义的行为和序列点,c++,undefined-behavior,c++-faq,sequence-points,C++,Undefined Behavior,C++ Faq,Sequence Points,什么是“序列点” 未定义的行为和序列点之间的关系是什么 我经常使用有趣而复杂的表达式,比如a[++I]=I,让自己感觉更好。我为什么要停止使用它们 如果你读过这篇文章,一定要访问后续问题 (注意:这是一个条目。如果您想对在此表单中提供常见问题解答的想法提出批评,则可以在此处进行评论。该问题的答案将在中进行监控,其中常见问题解答的想法是从中开始的,因此您的答案很可能会被提出此想法的人阅读。) C++98和C++03 此答案适用于C++版本的旧版本。标准的C++11和C++14版本没有正式包含“序列
a[++I]=I代码>,让自己感觉更好。我为什么要停止使用它们
如果你读过这篇文章,一定要访问后续问题
(注意:这是一个条目。如果您想对在此表单中提供常见问题解答的想法提出批评,则可以在此处进行评论。该问题的答案将在中进行监控,其中常见问题解答的想法是从中开始的,因此您的答案很可能会被提出此想法的人阅读。)
C++98和C++03
此答案适用于C++版本的旧版本。标准的C++11和C++14版本没有正式包含“序列点”;操作是“在之前排序”或“未排序”或“不确定排序”。净效果基本相同,但术语不同
免责声明:好的。这个答案有点长。所以在阅读时要有耐心。如果你已经知道这些事情,再读一遍也不会让你发疯
先决条件:基本知识
什么是序列点?
标准上说
在执行序列中称为序列点的特定点上,先前评估的所有副作用
应完整,且未发生后续评估的副作用。(§1.9/7)
副作用?什么是副作用?
表达式的求值会产生一些结果,此外,如果执行环境的状态发生变化,则表示表达式(其求值)有一些副作用
例如:
int x = y++; //where y is also an int
int x = 5, y = 6;
int z = x++ + y++; //it is unspecified whether x++ or y++ will be evaluated first.
除了初始化操作外,y
的值由于++
运算符的副作用而改变
到目前为止还不错。继续讨论序列点。公司lang.c作者Steve Summit给出的顺序点的替代定义:
序列点是一个时间点,在这个时间点上,尘埃已经沉淀下来,到目前为止已经看到的所有副作用都保证是完全的
C++标准中列出的公共序列点是什么?
这些是:
- 在完整表达式(
§1.9/16
)的求值结束时(完整表达式是不是另一个表达式的子表达式的表达式。)1
例如:
int a = 5; // ; is a sequence point here
- 在计算第一个表达式(
§1.9/18
)2之后,计算下列表达式中的每一个表达式
a&b(§5.14)
a|b(§5.15)
a?b:c(§5.16)
a,b(§5.18)
(这里a,b是逗号运算符;在func(a,a++)
中,
不是逗号运算符,它只是参数a
和a++
之间的分隔符。因此,在这种情况下,行为是未定义的(如果a
被视为基本类型))
- 在函数调用时(无论函数是否内联),在计算所有函数参数(如果有)之后
在执行函数体中的任何表达式或语句之前发生(
§1.9/17
)
1:注意:完整表达式的求值可以包括非词汇性子表达式的求值
完整表达的一部分。例如,计算默认参数表达式(8.3.6)所涉及的子表达式被认为是在调用函数的表达式中创建的,而不是在定义默认参数的表达式中创建的
2:所示的操作员是内置操作员,如第5条所述。当其中一个运算符在有效上下文中重载(第13条)从而指定用户定义的运算符函数时,表达式指定函数调用,操作数形成参数列表,它们之间没有隐含的序列点
什么是未定义的行为?
本标准将第1.3.12节中未定义的行为定义为
行为,如使用错误的程序结构或错误的数据时可能出现的行为,本国际标准对此不作要求3
当出现以下情况时,也可能会出现未定义的行为
国际标准省略了对行为的任何明确定义的描述
3:允许的未定义行为范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行期间以环境特有的记录方式(带或带)进行行为-
(发出诊断消息时)终止转换或执行(发出诊断消息时)
简而言之,未定义的行为意味着任何事情都可能发生,从你鼻子里飞出的守护进程到你女朋友怀孕
未定义的行为和序列点之间的关系是什么?
在我开始之前,你必须知道两者之间的区别
您还必须知道,未指定单个运算符的操作数和单个表达式的子表达式的求值顺序,以及副作用发生的顺序
例如:
int x = y++; //where y is also an int
int x = 5, y = 6;
int z = x++ + y++; //it is unspecified whether x++ or y++ will be evaluated first.
另一个例子
现在§5/4
中的标准是
- 1) 在上一个序列点和下一个序列点之间,通过计算表达式,标量对象的存储值最多修改一次。
这是什么意思
非正式地说,这意味着在两个序列点之间,一个变量不能被修改多次。
在表达式语句中,下一个序列点通常位于t
std::printf("%d %d", i,++i); // invokes Undefined Behaviour because of Rule no 2
a[i] = i++ // or a[++i] = i or a[i++] = ++i etc
int x = i + i++ ;// Similar to above
int main()
{
int num = 19 ;
num = (num << 3) + (num >> 3);
}
int i = 5, v[10] = { };
void f(int, int);
f (a,b)
a[++i] = i;
i = i++ + 1; // the behavior is undefined
i = i++ + 1; // the value of i is incremented
i = i++ + i; // the behavior is undefined