功能参数评估顺序

C/C++ ,函数的参数是否有固定的顺序? 我的意思是,标准是什么意思? 是left-to-right还是right-to-left ? 我从书中得到混乱的信息。

是否有必要使用stack only来实现function callC/C++标准对此有何评论?

C和C ++是两种完全不同的语言; 不要认为相同的规则总是适用于两者。 但是,在参数评估顺序的情况下:

C99:

6.5.2.2函数调用

10实际参数中的函数标识符,实际参数和子表达式的评估顺序是未指定的,但在实际调用之前有一个顺序点。

[ 编辑 ] C11(草案):

6.5.2.2函数调用

10在函数标识符和实际参数的评估之后,在实际调用之前有一个序列点。 在调用函数的主体执行之前或之后,在调用函数(包括其他函数调用)中的每个评估都未被特别排序,相对于被调用函数的执行被不确定地排序。 94)

换句话说,函数执行不会互相“交错”。

C ++:

5.2.2函数调用

8参数评估的顺序是未指定的。 参数表达式评估的所有副作用在输入函数之前生效。 未指定后缀表达式和参数表达式列表的评估顺序。

这两个标准都不要求使用硬件堆栈来传递函数参数; 这是一个实现细节。 C ++标准使用术语“展开堆栈”来描述从try块到throw-expression的路径上的自动创建对象的调用析构函数,但就是这样。 大多数流行的体系结构都是通过硬件堆栈传递参数的,但这不是通用的。

[ 编辑 ]

我从书中得到混乱的信息。

这并不令人惊讶,因为有关C语言的书籍中有90%是简单的废话

尽管语言标准对于学习 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)); 

这段代码非常糟糕。 它依赖于打印参数的评估顺序。 它将打印“1 1”(从右到左)或“2 2”(从左到右), 我们不知道哪个 。 标准保证的唯一的事情就是在调用print()之前,都完成了对func()的调用。

解决方案是要知道订单是不确定的,并编写不依赖于评估顺序的程序。 例如:

 int val1 = *func(1); int val2 = *func(2); print(val1, val2); // Will always print "1 2" on any compiler. 

是否有必要使用堆栈来实现函数调用? C / C ++标准对此有何评论?

这被称为“调用约定”,并没有任何标准指定的。 参数(和返回值)是如何传递的,完全取决于实现。 它们可以通过CPU寄存器或堆栈传递,或以其他方式传递。 调用者可能是负责推入/弹出堆栈参数的人,也可能是该函数的责任人。

函数参数的评估顺序只与调用约定有关,因为评估发生函数被调用之前 。 但另一方面,作为一个例子,某些编译器可以选择将最右边的参数放在CPU寄存器中,其余的放在堆栈上。

只是说C语言,函数参数内部的评估顺序依赖于编译器。 来自Brian KernighanDennis Ritchie 的C编程语言 ;

同样,函数参数的求值顺序没有被指定,所以语句

printf("%d %d\n", ++n, power(2, n)); /*WRONG */

可以用不同的编译器产生不同的结果,这取决于n在调用之前是否递增。 解决办法当然是写

++n;

printf("%d %d\n", n, power(2, n));