我认为它应该是01,但有人说它“未定义”,有什么原因吗?
答案 0 :(得分:8)
c++
既是增量又是赋值。当分配发生时(在该行上的其他代码之前或之后)由编译器决定。它可以在cout <<
之后或之前发生。
这可以在C99标准中找到 http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf
您可以在第28页的pdf或第5.1.2.3节
中找到它p的实际增量可以在前一个序列点和下一个序列点之间的任何时间发生
由于有人要求提供C ++标准(因为这是一个C ++问题),所以可以在第1.9.15页第10节(或pdf格式的24)中找到
单个运算符的操作数和单个表达式的子表达式的评估是无序的
它还包括以下代码块:
i = v[i++]; // the behavior is undefined
i = 7, i++, i++; // i becomes 9
i = i++ + 1; // the behavior is undefined
我觉得C99标准的解释更清楚,但两种语言都是如此。
答案 1 :(得分:4)
如果您修改一个值然后在没有插入序列点的情况下读取它(或尝试再次修改它),则它是未定义的行为。 C ++中的序列点的概念有点技术性(您可以阅读一些关于它的here),但最重要的是流插入(<<
)不是一个序列点。
这是未定义行为的原因是因为,在没有序列点的情况下,允许编译器以其认为合适的任何方式重新排序操作。也就是说,允许检索c
的值(并在第二次插入时保留它)然后在执行c++
之后获取第一次插入的值。因此,您无法确定在第二次插入的c
值之前或之后是否会发生增量。
答案 2 :(得分:1)
行为已定义但未指定。未指定评估表达式中“c”的两种用法的相对顺序。但是,如果将其转换为功能表示法,则如下所示:
cout.operator<<(c++).operator<<(c);
在评估函数的参数和执行函数体之间存在一个序列点,并且函数体不是交错的,因此结果只是未指定的,而不是未定义的行为。
如果您没有重载运算符:
int c=0;
int a = c++ << c;
然后行为将是未定义的,因为修改和使用c
的值而没有插入序列点。
编辑:序列litb
提出错误。标准指定(§1.9/ 17):“当调用函数时(无论函数是否为内联函数),在执行任何表达式之前发生的所有函数参数(如果有)的评估之后都有一个序列点或函数体中的语句。“
这清楚地写入了对参数进行评估的想法,然后(紧接着之后)执行函数体。他建议的序列,其中一个函数的参数被评估,然后是另一个函数的参数,然后执行两个函数体似乎没有打算,但也不被禁止。然而,这没有任何改变 - 要求仍然是:“...在评估所有函数参数(如果有的话)之后有一个序列点......”
关于正文执行的后续语言在评估所有函数参数后不会删除对序列点的要求。 所有其他评估,无论是函数体还是其他函数参数都遵循该序列点。我可以像任何人一样迂腐和乖乖地误读了明确的意图(但不是相当陈述) - 但我无法想象“在评估所有功能之后是否有一个序列点参数“可以读作含义”在评估所有函数参数后没有序列点。“
Neil的观点当然是正确的:我上面使用的语法是成员函数。对于非成员重载,语法更像是:
operator<<(operator<<(cout,c++), c);
但这并没有消除对序列点的要求。
就未指定而言:它非常简单:在评估所有函数参数之后有一个序列点,因此必须完全评估一个函数调用的所有参数(包括所有副作用),然后是另一个函数的参数可以评估调用(考虑到来自另一方的任何副作用) - 但是没有要求WHICH函数调用的参数必须先评估或秒,所以它可以是c
,然后是c++
,或者它可以是c++
,然后是c
- 但它必须是一个或另一个,而不是交错。
答案 3 :(得分:1)
未定义的原因是编译器可以按任何顺序自由计算函数参数。考虑一下你在哪里调用一个函数(因为你是,但是在函数语法中它更容易设想):
cout.output(c++).output(c);
编译器可能以相反的顺序,转发顺序或其他任何方式命中参数。它可以在计算第二个输出的参数之前调用第一个输出,或者它可以同时执行两个然后调用。
答案 4 :(得分:0)
我认为, F(C ++); 相当于: F(C); c + = 1;
和 F(C ++,C ++); 相当于: F(C,C); c + = 1; c + = 1;
但可能是这样的 F(C ++,C ++); 变 F(C,C + 1); c + = 2;
gcc和clang的实验,首先在C
#include <stdio.h>
void f(int a, int b) {
printf("%d %d\n",a,b);
}
int main(int argc, char **argv) {
int c = 0;
f(c++,c++);
return 0;
}
和C ++
#include <iostream>
int main(int argc, char **argv) {
int c = 0;
std::cout << c++ << " " << c++ << std::endl;
return 0;
}
很有意思,因为gcc和g ++编译结果 1 0 而clang编译的结果 0 1