C++标准中的$ 3.6.1/1节,
程序应包含一个名为main的全局函数,它是程序的指定开始.
现在考虑这段代码,
int square(int i) { return i*i; }
int user_main()
{
for ( int i = 0 ; i < 10 ; ++i )
std::cout << square(i) << endl;
return 0;
}
int main_ret= user_main();
int main()
{
return main_ret;
}
Run Code Online (Sandbox Code Playgroud)
此示例代码执行我打算执行的操作,即在进入main()应该是程序"开始" 的函数之前打印从0到9的整数平方.
我还用-pedantic选项GCC 4.5.0 编译它.它没有错误,甚至没有警告!
所以我的问题是,
这段代码真的符合标准吗?
如果它符合标准,那么它是否会使标准所说的无效?main()不是这个计划的开始!user_main()在执行之前执行main().
我知道要初始化全局变量main_ret,use_main()首先执行,但这是完全不同的事情; 关键是,它确实使标准中的引用语句$ 3.6.1/1无效,因为main() …
我很好奇初始化列表和序列点.我刚才读到初始化程序列表中的评估顺序是从左到右.如果是这样,那么评估点之间肯定会有某种序列点,我错了吗?那么说是以下有效代码?是否有任何导致其未定义的行为?
int i = 0;
struct S {
S(...) {}
operator int() { return i; }
};
int main() {
i = S{++i, ++i};
}
Run Code Online (Sandbox Code Playgroud)
任何和所有回复都表示赞赏.
考虑以下代码:
int main()
{
int count = 0 ;
int arrInt[2] = { count++, count++ } ;
return 0 ;
}
Run Code Online (Sandbox Code Playgroud)
如果我们使用clang -std=c++03它编译代码,则会产生以下警告(实时示例):
warning: multiple unsequenced modifications to 'count' [-Wunsequenced]
int arrInt[2] = { count++, count++ } ;
^ ~~
Run Code Online (Sandbox Code Playgroud)
我不是在提倡这样的代码,但是在另一个问题中出现了类似的代码,并且对于是否根据标准C ++ 11进行定义存在分歧。在C ++ 11中,根据初始化程序中的多个突变是否列出未定义的行为,此行为是定义良好的行为,并且如果我使用该警告,则该警告消失了。-std=c++11
如果我们看一下C ++ 11 之前的标准草案,它没有覆盖initializer-list的相同语言,那么似乎我们剩下的是Chapter 5 Expressions第4段:
除非另有说明,否则未指定各个运算符的操作数和各个表达式的子表达式的求值顺序以及发生副作用的顺序。57)在上一个序列点与下一个序列点之间,标量对象最多应通过表达式的计算修改其存储值。此外,应仅访问先验值以确定要存储的值。对于完整表达式的子表达式的每个允许的排序,都应满足本段的要求;否则,行为是不确定的。
为了使这个未定义,我们似乎必须将其解释count++, count++ …