C++ C++;-奇怪的是,输入被颠倒了
我发现了一些奇怪的东西,我测试了以下代码:C++ C++;-奇怪的是,输入被颠倒了,c++,input,output,C++,Input,Output,我发现了一些奇怪的东西,我测试了以下代码: #include <iostream> using namespace std; int main() { int i=0, a[5]; cin>>a[i++]>>a[i++]>>a[i++]; for(int j=0; j<i; j++){ cout<<a[j]<<endl; } } 然后将输入反转如下: 3 2 1 我
#include <iostream>
using namespace std;
int main() {
int i=0, a[5];
cin>>a[i++]>>a[i++]>>a[i++];
for(int j=0; j<i; j++){
cout<<a[j]<<endl;
}
}
然后将输入反转如下:
3
2
1
我认为它的输出应该与以下代码相同:
#include <iostream>
using namespace std;
int main() {
int i=0, a[5];
cin>>a[i++]; cin>>a[i++]; cin>>a[i++];
for(int j=0; j<i; j++){
cout<<a[j]<<endl;
}
}
#包括
使用名称空间std;
int main(){
int i=0,a[5];
cin>>a[i++];cin>>a[i++];cin>>a[i++];
对于(int j=0;j这感觉像是未定义的行为和编译器依赖:
cin>>a[i++]>>a[i++]>>a[i++];
(大师们,如果我错了,请纠正我)语句的行为cin>>a[I++]>>a[I++]>>a[I++];
实际上没有定义。这是因为没有序列点
您不知道i
何时递增,因此您的输出并不令人惊讶
在同一语句中修改和使用变量时,会导致未定义的行为,请参见。
在下面的语句中,我被修改了3次,并被访问了3次
cin>>a[i++]>>a[i++]>>a[i++];
我想下面的代码可以很好地工作
#include <iostream>
using namespace std;
int main() {
int i=0, a[5];
cin>>a[0]>>a[1]>>a[2];
i=3;
for(int j=0; j<i; j++){
cout<<a[j]<<endl;
}
}
#包括
使用名称空间std;
int main(){
int i=0,a[5];
cin>>a[0]>>a[1]>>a[2];
i=3;
对于(int j=0;j
只是语法上的糖
cin.operator>>(a[i++]).operator>>(a[i++]).operator>>(a[i++]);
现在,对operator>
的三个调用肯定是从左到右执行的,但是三个参数a[i++]
可以按任何顺序计算。让我们调用参数x
,y
和z
:
cin.operator>>(x).operator>>(y).operator>>(z);
您可能希望编译器将x
、y
和z
替换为以下内容:
int& x = a[i];
i++;
int& y = a[i];
i++;
int& z = a[i];
i++;
但事实上,编译器给了你更多的自由。在你的例子中,它选择了:
int& z = a[i];
i++;
int& y = a[i];
i++;
int& x = a[i];
i++;
正如James Kanze指出的,它也可以选择:
int& x = a[i];
int& y = a[i];
int& z = a[i];
i++;
i++;
i++;
如前所述,代码具有未定义的行为,因为未指定函数参数的求值顺序,并且由于应用后增量运算符的副作用,因此未以确定性方式排序
我将如何解释结果
表情
cin>>a[i++]>>a[i++]>>a[i++];
如果我们使用函数表示法,则等价于下面的表达式
cin.operator >>( a[i++] ).operator >>( a[i++] ).operator >>( a[i++] );
函数参数的求值顺序没有指定。因此,一些编译器从右向左求值,而另一些编译器从左向右求值
很明显,编译器从右到左计算函数参数。第一个是最右边函数的参数
cin.operator >>( a[i++] ).operator >>( a[i++] ).operator >>( a[0] );
对参数求值后,编译器应用副作用。i等于1。然后编译器对第二个函数的参数求值,得到
cin.operator >>( a[i++] ).operator >>( a[1] ).operator >>( a[0] );
最后,在求值之后,第一个函数调用的参数将
cin.operator >>( a[2] ).operator >>( a[1] ).operator >>( a[0] );
变量i等于3
但是,正如我所说的,函数参数的求值顺序也没有指定,其他编译器可以将此表达式表示为
cin.operator >>( a[0] ).operator >>( a[1] ).operator >>( a[2] );
因此结果可能不同,程序的行为也未定义。@juanchopanza是的,但在调用第一个操作符>
时,a[i++]
已经计算过的参数介于1和3之间。@FredOverflow这不会导致行为未指定吗?@juanchopanza参数的计算顺序确实未指定,但如果多个参数访问同一对象,并且其中至少有一个参数是写入的,则会出现未定义的行为(除非写访问和读访问之间有一个序列点)。@juanchopanza序列点(或C++11中的sequenced before概念)创建一个偏序。对操作符>
的所有调用都是在提供其参数的a[i++]
之后排序的,但是a[i++]
在第一次调用之前。(对操作符>>
的调用是有序的,因为存在数据依赖关系:第二次调用的第一个参数是第一次调用的返回值。)这是未定义的行为。我不确定在这里是否会使用表达式“编译器依赖”,因为这听起来更像是“实现定义的”(这意味着不同的实现可能会做不同的事情,但它们必须记录下来)。特别是,这里的结果可能会因优化标志的不同而有所不同,甚至会因周围语句中的代码而有所不同。实际上,考虑到我们有未定义的行为,编译器可以随意执行任何操作,包括生成崩溃的代码。(在某些情况下,G++会在识别未定义的行为时执行此操作。)更可能的是,编译器可以做一些与int&x=a[i]、&y=a[i]、&z=a[i];i+=3;
等效的事情。
cin.operator >>( a[2] ).operator >>( a[1] ).operator >>( a[0] );
cin.operator >>( a[0] ).operator >>( a[1] ).operator >>( a[2] );