可能重复:
未定义的行为和序列点
#include <iostream>
using namespace std;
int main()
{
int x[3] = {};
int i=0;
x[i] = i++;
cout << x[0] << " " << x[1] << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
键盘给我这个:第9行:警告:'i'上的操作可能未定义为什么操作未定义?
在我对一个问题的回答中,我解释了当 postfix ++ 在与语句同一行的全局变量上使用时发生的情况return。
C11的资料性附录C指出a之后紧接着有一个序列点return,并参考规范性章节6.8.6.4,其中找不到有关序列点的文本。
在 C 标准中的哪里可以找到规范性文本,说明return语句后有一个序列点?
(我只在 7.1.4/3 找到了针对库函数说明这一点的规范文本,作为一种特殊情况。)
对于C++ 03,标准说,在&&运算符的左右操作数之间有一个序列点,因此左操作符的所有副作用都发生在访问右操作符之前.
所以
int i = 0;
if (++i && i--)
std::cout << i;
Run Code Online (Sandbox Code Playgroud)
定义明确,保证输出0.
但是这个问题是什么:只有左操作数不是,才评估右操作数0?它似乎是一个细节,但对我来说,标准只保证操作数之间的序列点,而不是右操作数永远不会依赖于左操作数进行评估/访问.
例如
int arr[10];
int pos; // somehow set to a value from 0 to 10
while (pos < 10 && arr[pos] != 0)
pos++;
Run Code Online (Sandbox Code Playgroud)
这个定义得很好吗?pos可能是从开始10或到达10.左操作数没有副作用,与右操作数一致.我arr[10] != 0有从未履行的保证吗?
编辑:
感谢评论和回答,现在很清楚:
5.14p2: "The result is a bool. If the second expression is evaluated,
every value computation …Run Code Online (Sandbox Code Playgroud) c++ operator-precedence undefined-behavior sequence-points c++03
这是一个非常简单的问题,但在序列点上甚至有一些疑问.
int a[3] = {1,2,4};
printf("%d",++a[1]);
Run Code Online (Sandbox Code Playgroud)
3
Run Code Online (Sandbox Code Playgroud)
这是一个有效的c语句,我得到输出3,这意味着它是相同的
++(a[1])
Run Code Online (Sandbox Code Playgroud)
但是这是如何可能的,因为我们有一个预增量运算符,必须先递增第a一个,然后必须发生解除引用.
请纠正我的疑问.我们怎么样3?
标准C++ 11是否保证在开始执行函数之前已经创建了所有3个临时对象?
即使临时对象传递为:
#include <iostream>
using namespace std;
struct T {
T() { std::cout << "T created \n"; }
int val = 0;
~T() { std::cout << "T destroyed \n"; }
};
void function(T t_obj, T &&t, int &&val) {
std::cout << "func-start \n";
std::cout << t_obj.val << ", " << t.val << ", " << val << std::endl;
std::cout << "func-end \n";
}
int main() {
function(T(), T(), T().val);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
T created …Run Code Online (Sandbox Code Playgroud) 维基百科说:
在计算机科学中,如果一个操作、函数或表达式在其本地环境之外修改了某些状态变量值,则该操作、函数或表达式被认为具有副作用,也就是说,除了返回一个值(主要效果)之外,还具有可观察到的效果。操作的调用者。
但是我们如何访问本地环境之外的变量,任何人都可以解释这种情况,副作用,主要效果和序列点吗?
根据this answer,以下是标准中描述的序列点:
在函数调用和实际调用中的函数指示符和实际参数的评估之间;
在运算符 &&、|| 和 , 的第一个和第二个操作数的计算之间;
在条件 ?: 运算符的第一个操作数的评估与第二个和第三个操作数中的任何一个评估之间;
完整声明符的结束;
在完整表达式的求值和要求值的下一个完整表达式之间。以下是完整的表达:
在库函数返回之前;
在与每个格式化输入/输出函数转换说明符相关联的动作之后;
在每次调用比较函数之前和之后,以及在对比较函数的任何调用和作为参数传递给该调用的对象的任何移动之间。
该标准从未明确提到分号是一个序列点,但是已经说明的各种序列点暗示分号确实是一个序列点。
那么,分号是在break;还是continue;序列点中?
#include<stdio.h>
int main()
{
int a=4;
int b=4;
int c= a++ < ++b? 1 : 0;
printf ("%d",c);
}
Run Code Online (Sandbox Code Playgroud)
已知在 处有一个序列点?,这意味着前缀和后缀操作都必须在该点完成。还知道(?)b在比较之前增加。然而,是a在比较之前还是之后增加呢?
如果在测试之前递增<,则布尔值计算结果为 false 并c设置为 0,否则为 true 并c设置为 1。在我的编译器中,它计算结果为 true,这意味着a++在比较操作之后执行并c设置为1.
但这种行为是规范的一部分吗?
我修改为
#include<stdio.h>
int main()
{
int a=4;
int b=4;
int d=2;
int c= a++ + d < ++b + d? 1 : 0;
printf ("%d",c);
}
Run Code Online (Sandbox Code Playgroud)
它的计算结果仍然为 1。后缀必须在 之前完成?,但这真的确保它在比较之后发生吗<?
c conditional-operator unary-operator sequence-points postfix-operator
即与此类似的代码,使打印输出不确定.
int a=41; a++ & printf("%d\n", a);
Run Code Online (Sandbox Code Playgroud)
希望这不是一个问题的愚蠢,因为我不知道这个操作到底是什么.在此先感谢您的反馈!
我一直在尝试一些代码混淆的比赛(我知道这不是一个好的编程实践,但它是一个挑战我和一个朋友竞争,所以没有必要指出明显的),并在其中一个,我发现表达式有以下奇怪的行为(代码已减少到仍然重现行为的行为)t-scanf("%d",t--?&N:&t):
int main(int t, int N){
printf("%d\n",t-scanf("%d",t--?&N:&t));
}
int main(int t, int N){
printf("%d\n",t-scanf("%d",t--?&N:&t)==0);
}
int main(int t, int N){
printf("%d\n",t-scanf("%d",t--?&N:&t)!=0);
}
Run Code Online (Sandbox Code Playgroud)
如果我执行第一个部分,将打印0,即表达式的计算结果为0.
在第二个上,将打印0,即表达式不计算0.
在第三个,将打印1,这意味着表达式不会计算为0.
所以问题是:这些代码有什么问题?
sequence-points ×10
c ×7
c++ ×3
break ×1
c++03 ×1
c++11 ×1
continue ×1
gcc ×1
obfuscation ×1
return ×1
scope ×1
side-effects ×1
standards ×1