C++11以前的序列点
2016-02-28 10:49
197 查看
首先看wiki:
https://en.wikipedia.org/wiki/Sequence_point
简单翻译:
1.&&(与)、||(或)运算符的左右两边之间有序列点。(为了实现短路逻辑)逗号表达式也是一个序列点。例如, *p++ != 0 && *q++ != 0, *p++!=0这个子表达式的所有副作用完成之后,才会对q进行计算。
2.问号运算符的第一个判断表达式之后,和第二个或者第三个语句之间。例如, a+(*p++)?(*p++):0,在第一个*p++之后有序列点,所以当执行第二个*p++时,第一个自增操作已经完成。
3.在所有的“全表达式”之后。包括表达式语句,如a=b;,和返回值语句,if,switch,while,do-while的控制表达式,以及for循环里的3个语句。
4.调用函数之前。但函数中多个参数表达式的执行顺序是未定义的,不过它们在进入函数调用栈之前肯定全部执行完了。在f(i++) + g(j++) + h(k++)中,f有个参数i,i在进入函数f之前已经自增完成。类似地,j和k也是同样。但是,f、g、h 3个函数调用以什么顺序发生,则是未定义的。导致i、j、k以什么顺序自增也变成未定义了。在函数f执行的时候,j和k可能已经自增,也可能没有。注意,f(a,b,c)中,逗号不是逗号表达式,只是参数的分隔符,因此a、b、c3个表达式的执行顺序是未定的。
5.函数返回,当返回值拷贝到调用栈后。(在C++标准中明确规定,在C中则只是隐含推论出的,未明确规定)
6.初始化结束知乎。如int a = 5;
7.多个声明。如int x=a++,y=a++;,这跟逗号表达式不一样,但也是序列点。
8.在I/O格式化中。例如,在printf(”foo %n %d”, &a, 42);在%n求值以后,尚未打印42之前,有一个序列点。
特别注意:
* f(i++) + g(j++) + h(k++) 三个函数执行顺序未定义
* printf(“%d, %d, %d”, a++, –b, a++), 3个参数表达式执行顺序未定义
* cout << a++ << b++ << c++; 3个表达式的顺序也未定义。因为相当于cout.operator<<(a++). operator<<(b++). operator<<(c++),又相当于operator<<( operator<<( operator<<(cout, a++), b++), c++),<<相当于两个参数的函数。
典型的未定义行为:
Undefined behavior
1) If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.两个序列点之间,对同一个变量只能写一次。多次修改会导致未定义行为。
i = ++i + i++; // undefined behavior
i = i++ + 1; // undefined behavior
f(++i, ++i); // undefined behavior
f(i = -1, i = -1); // undefined behavior
2) If a side effect on a scalar object is unsequenced relative to a value computation using the value of the same scalar object, the behavior is undefined.两个序列点之间,对同一个变量又读又写,那么也是未定义的。因为不知道读先发生还是写先发生。
f(i, i++); // undefined behavior
a[i] = i++; // undefined bevahior
在单例模式的double check locking中,之所以会出错,就是因为p = new T;这个语句结束时有个序列点,但未结束之前,赋值和构造谁先发生,就是未定义的了。
https://en.wikipedia.org/wiki/Sequence_point
简单翻译:
C和C++中的序列点
在C和C++中,下列位置被认为是序列点。(注意,被重载的运算符,相当于函数调用,它们引入的序列点与运算符没有关系,而与函数调用一致)1.&&(与)、||(或)运算符的左右两边之间有序列点。(为了实现短路逻辑)逗号表达式也是一个序列点。例如, *p++ != 0 && *q++ != 0, *p++!=0这个子表达式的所有副作用完成之后,才会对q进行计算。
2.问号运算符的第一个判断表达式之后,和第二个或者第三个语句之间。例如, a+(*p++)?(*p++):0,在第一个*p++之后有序列点,所以当执行第二个*p++时,第一个自增操作已经完成。
3.在所有的“全表达式”之后。包括表达式语句,如a=b;,和返回值语句,if,switch,while,do-while的控制表达式,以及for循环里的3个语句。
4.调用函数之前。但函数中多个参数表达式的执行顺序是未定义的,不过它们在进入函数调用栈之前肯定全部执行完了。在f(i++) + g(j++) + h(k++)中,f有个参数i,i在进入函数f之前已经自增完成。类似地,j和k也是同样。但是,f、g、h 3个函数调用以什么顺序发生,则是未定义的。导致i、j、k以什么顺序自增也变成未定义了。在函数f执行的时候,j和k可能已经自增,也可能没有。注意,f(a,b,c)中,逗号不是逗号表达式,只是参数的分隔符,因此a、b、c3个表达式的执行顺序是未定的。
5.函数返回,当返回值拷贝到调用栈后。(在C++标准中明确规定,在C中则只是隐含推论出的,未明确规定)
6.初始化结束知乎。如int a = 5;
7.多个声明。如int x=a++,y=a++;,这跟逗号表达式不一样,但也是序列点。
8.在I/O格式化中。例如,在printf(”foo %n %d”, &a, 42);在%n求值以后,尚未打印42之前,有一个序列点。
特别注意:
* f(i++) + g(j++) + h(k++) 三个函数执行顺序未定义
* printf(“%d, %d, %d”, a++, –b, a++), 3个参数表达式执行顺序未定义
* cout << a++ << b++ << c++; 3个表达式的顺序也未定义。因为相当于cout.operator<<(a++). operator<<(b++). operator<<(c++),又相当于operator<<( operator<<( operator<<(cout, a++), b++), c++),<<相当于两个参数的函数。
典型的未定义行为:
Undefined behavior
1) If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.两个序列点之间,对同一个变量只能写一次。多次修改会导致未定义行为。
i = ++i + i++; // undefined behavior
i = i++ + 1; // undefined behavior
f(++i, ++i); // undefined behavior
f(i = -1, i = -1); // undefined behavior
2) If a side effect on a scalar object is unsequenced relative to a value computation using the value of the same scalar object, the behavior is undefined.两个序列点之间,对同一个变量又读又写,那么也是未定义的。因为不知道读先发生还是写先发生。
f(i, i++); // undefined behavior
a[i] = i++; // undefined bevahior
在单例模式的double check locking中,之所以会出错,就是因为p = new T;这个语句结束时有个序列点,但未结束之前,赋值和构造谁先发生,就是未定义的了。
相关文章推荐
- 如何加快 C++ 代码的编译速度
- [转]C++函数模板与模板函数
- C语言实现双向非循环链表的节点插入
- LeetCode:39. Combination Sum(C++版本)
- C++笔记:2
- C语言中进程与系统调用
- C/C++中的数据存储方式
- C++学习笔记(1)---基本数据类型
- VC++6.0调用Web Services(转)
- Android编译本地C++程序方法
- c语言:两个整数的正整数差(单分支结构)
- 《核心分析》第一周
- Effective C++: 限定作用域的枚举类型.
- c++程序员不可不知的101条经验之13章 高级特性
- C语言 单链表的实现
- 关于逆波兰式的c++实现
- 1073. Scientific Notation (20)
- C++中const和指针*的组合问题
- 5.5
- 5.4