Tag: sequence points

未定义的行为和序列点

什么是“序列点”? 未定义的行为和序列点之间的关系是什么? 我经常使用像a[++i] = i;这样有趣而复杂的表达a[++i] = i; ,让自己感觉更好。 我为什么要停止使用它们? 如果您已阅读此内容,请务必访问后续问题重新加载未定义的行为和序列点 。 (注意:这是Stack Overflow的C ++常见问题解答的一个条目。如果你想批评在这种forms下提供常见问题解答的想法,那么发布所有这些的meta上的post就是这样做的地方。这个问题在C ++聊天室中受到监控,其中FAQ的想法首先出现在那里,所以你的答案很可能被那些提出想法的人阅读。)

这些作业之间是否有一个序列点?

以下代码中的两个赋值之间是否存在序列点: f(f(x=1,1),x=2);

int a = 1,b = a ++; 调用未定义的行为?

int a=1, b=a++; 调用未定义的行为? 在a的初始化和b的初始化程序中a访问和修改之间没有序列点介入,但据我所知,初始化不是对象的“修改”; 指定初始值设定项以提供对象的“初始值”。 根据6.7.8初始化,第8段: 初始值设定项指定存储在对象中的初始值。 在对对象进行任何访问之前对“初始”进行排序似乎是合理的。 此问题是否已经考虑过,是否有可接受的解释?

在ANSI C中foo(i ++)+ foo(i ++)是否未定义?

这是一个示例代码段: int i = 4,b; b = foo(i++) + foo(i++); 我很确定它不是未定义的,因为在调用foo之前有一个序列点。 但是,如果我使用-Wall标志编译代码,则会生成编译器警告, warning: operation on ‘i’ may be undefined 。 我意识到它may ,但我只想仔细检查一下我是否正确。

函数调用的序列点?

这是另一个序列点问题,但是一个相当简单的问题: #include void f(int p, int) { printf(“p: %d\n”, p); } int g(int* p) { *p = 42; return 0; } int main() { int p = 0; f(p, g(&p)); return 0; } 这是未定义的行为吗? 或者对g(&p)的调用是否作为序列点?

printf中的序列点

我在这里读到有一个序列点: 在与输入/输出转换格式说明符相关联的操作之后。 例如,在表达式printf(“foo %n %d”, &a, 42) ,在打印42之前评估%n之后存在序列点。 但是,当我运行此代码时 : int your_function(int a, int b) { return a – b; } int main(void) { int i = 10; printf(“%d – %d – %d\n”, i, your_function(++i, ++i), i); } 而不是我期望得到的: 12 – 0 – 12 这意味着没有为转换格式说明符创建序列点。 http://en.wikipedia.org是错误的,或者我只是误解了某些内容,或者在这种情况下gcc是否不合规(顺便提一下Visual Studio 2015会产生相同的意外结果)? 编辑: 我理解,对your_function的参数的计算顺序和分配给参数的顺序是未定义的。 我不是在问我为什么我的中期是0.我问为什么其他两个术语都是12。

序列点和副作用:C11的安静变化?

C99§6.5 表达式 (1)表达式是操作符和操作数的序列,其指定值的计算,或指定对象或函数,或者生成副作用,或执行其组合。 (2)在前一个和下一个序列点之间,一个对象的存储值最多只能通过表达式的计算来修改一次。 72)此外,先前的值应该是只读的,以确定要存储的值。 73) 用脚注 72)浮点状态标志不是对象,可以在表达式中多次设置。 73)此段落呈现未定义的语句表达式,如 i = ++i + 1; a[i++] = i; 同时允许 i = i + 1; a[i] = i; C11§6.5改为((1)的文本有附录): (1)[…]运算符的操作数的值计算在运算符的结果的值计算之前被排序。 (2)如果对标量对象的副作用相对于对同一标量对象的不同副作用或使用相同标量对象的值进行的值计算未被排序,则行为未定义。 如果表达式的子表达式有多个允许的排序,则如果在任何排序中发生这种未测序的副作用,则行为是不确定的。 84) 其中C11中的脚注84与C99中的73相同。 我有点困惑……我把C11(2)看作是“[…](对同一个标量对象的不同副作用)或(使用相同标量对象的值进行值计算)[…]”甚至不允许foo = ++i (有副作用,我们根据更改的对象使用值)。 不过,我不是母语人士,所以如果能告诉我这句话应该如何“解析”会更好。 我理解C99,但我不太明白C11的措辞。 无论如何,实际问题:这是从C99到C11的变化,还是这些措辞相当? 如果是这样,为什么它会被改变? 如果没有,有人可以给出一个表达式的例子,这个表达式在C99中是UB但在C11中不是,反之亦然?

我应该使用哪些编译标志来避免运行时错误

刚刚在这里了解到-Wsequence-point comiplation标志会在代码调用UB时弹出警告。 我在类似的声明上尝试过 int x = 1; int y = x+ ++x; 它工作得非常好。 到目前为止,我只使用-ansi -pedantic -Wall编译gcc或g++ 。 你有没有其他有用的标志来使代码更安全和健壮?

表达式中有序列点a ^ = b ^ = a ^ = b,还是未定义?

据称“巧妙”(但实际上效率低下)交换两个整数变量而不是使用临时存储的方式通常涉及这一行: int a = 10; int b = 42; a ^= b ^= a ^= b; /*Here*/ printf(“a=%d, b=%d\n”, a, b); 但我想知道,复合赋值运算符如^=不是序列点,是吗? 这是否意味着它实际上是未定义的行为?

C中的序列点和副作用

在这个C-FAQ中给出了序列点 ; 标准规定: 在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的计算修改一次。 此外,只能访问先前值以确定要存储的值。 在例子中 i = i++; a[i] = i++; 从声明的第一句可以清楚地看出,这些例子是未定义行为的结果。 在解释声明的第二句时,据说; 第二句话说: 如果一个对象被写入一个完整的表达式,那么在同一个表达式中对它的任何和所有访问都必须直接参与计算要写入的值。 此规则有效地将法律表达式约束为在修改之前明显存在访问的表达式。 例如,旧备用 i = i + 1 是允许的,因为i的访问用于确定i的最终值。 这个例子 a[i] = i++ 是不允许的,因为i的一个访问(a [i]中的一个)与最终存储在i中的值无关(在i ++中发生),因此没有好的方法来定义。 我的问题是; 1.它是什么意思, 如果一个对象被写入一个完整的表达式,那么在同一个表达式中对它的任何和所有访问必须直接参与计算要写入的值。 ? 2.它是什么意思,例子a[i] = i++ 是不被允许的,因为i的一个访问(a [i]中的一个)与最终存储在i中的值无关(其中发生在i ++) 有人可以用一些简单的方法解释它吗?