Joh*_*ode 33
C和C++是两种完全不同的语言; 不要假设同样的规则总是适用于两者.但是,在参数评估顺序的情况下:
C99:
6.5.2.2函数调用
...
10函数指示符的评估顺序,实际参数和实际参数中的子表达式是未指定的,但在实际调用之前有一个序列点.
[ 编辑 ] C11(草稿):
6.5.2.2函数调用
...
10在评估函数指示符和实际参数之后但在实际调用之前有一个序列点.调用函数(包括其他函数调用)中的每个评估(在执行被调用函数的主体之前或之后没有特别排序)对于被调用函数的执行是不确定地排序的.94)
...
94)换句话说,函数执行不会相互"交错".
C++:
5.2.2函数调用
...
8参数的评估顺序未指定.参数表达式求值的所有副作用在输入函数之前生效.未指定后缀表达式和参数表达式列表的评估顺序.
两种标准都没有要求使用硬件堆栈来传递函数参数; 这是一个实现细节.C++标准使用术语"展开堆栈"来描述从try
块到throw-expression的路径上自动创建的对象的调用析构函数,但就是这样.最流行的架构确实通过硬件堆栈传递参数,但它不是通用的.
[ 编辑 ]
我从书中得到了令人困惑的信息.
这并不是最令人惊讶的,因为很容易就90%写的关于C的书只是废话.
虽然语言标准不是学习 C或C++的好资源,但对于像这样的问题很方便.官方™标准文件需要花钱,但有一些草稿可以在网上免费获得,并且应该足以满足大多数用途.
最新的C99草案(自原始出版物以来有更新)可在此处获得.最新的出版前C11草案(去年正式批准)可在此处获取.此处提供了公开可用的C++语言草案,尽管它有一个明确的免责声明,其中一些信息不完整或不正确.
保持安全:标准将其留给编译器来确定参数的计算顺序.因此,您不应该依赖特定的订单.
在 C/C++ 中,函数参数的求值有固定的顺序。我的意思是标准所说的是从左到右还是从右到左。我从书中得到的信息令人困惑。
不,函数参数(以及任何表达式中的两个子表达式)的求值顺序在 C 和 C++ 中是未指定的行为。用简单的英语来说,这意味着可以首先评估最左边的参数,也可以是最右边的参数,并且您无法知道哪个顺序适用于特定编译器。
例子:
static int x = 0;
int* func (int val)
{
x = val;
return &x;
}
void print (int val1, int val2)
{
cout << val1 << " " << val2 << endl;
}
print(*func(1), *func(2));
Run Code Online (Sandbox Code Playgroud)
这段代码非常糟糕。它依赖于打印参数的评估顺序。它将打印“1 1”(从右到左)或“2 2”(从左到右),但我们不知道是哪个。标准唯一保证的是对 func() 的两次调用都在对 print() 的调用之前完成。
解决这个问题的方法是注意顺序是未指定的,并编写不依赖于计算顺序的程序。例如:
int val1 = *func(1);
int val2 = *func(2);
print(val1, val2); // Will always print "1 2" on any compiler.
Run Code Online (Sandbox Code Playgroud)
函数调用是否必须仅使用堆栈来实现?C/C++ 标准对此有何规定?
这称为“调用约定”,标准中根本没有指定任何内容。如何传递参数(和返回值)完全取决于实现。它们可以在 CPU 寄存器或堆栈上或以其他方式传递。调用者可以负责将参数压入/弹出堆栈,也可以由函数负责。
函数参数的求值顺序仅与调用约定有一定关系,因为求值发生在调用函数之前。但另一方面,某些编译器可以选择将最右边的参数放入 CPU 寄存器中,并将其余参数放入堆栈中,例如。