Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 未定义的行为和序列点_C++_Undefined Behavior_C++ Faq_Sequence Points - Fatal编程技术网

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