函数参数求值顺序

Function argument evaluation order

本文关键字:顺序 参数 函数      更新时间:2023-10-16

我对调用c++函数时函数参数的评估顺序感到困惑。我可能解释错了什么,如果是这样的话,请解释一下。

作为一个例子,传奇的书《编程windows》;包含如下代码:

// hdc = handle to device context
// x, y = coordinates of where to output text
char szBuffer[64];
TextOut(hdc, x, y, szBuffer, snprintf(szBuffer, 64, "My text goes here"));

最后一个参数是

snprintf(szBuffer, 64, "My text goes here")

返回写入char[] szBuffer的字符数。它还写着"我的文本到这里"到char[] szBuffer。第四个参数是szBuffer,它包含要写入的文本。然而,我们可以看到szBuffer被填充在第五个参数中,告诉我们它是表达式

// argument 5
snprintf(szBuffer, 64, "My text goes here")

评估之前

// argument 4
szBuffer

好的,很好。总是这样吗?求值总是从右到左的?查看默认调用约定__cdecl:

__cdecl调用约定的主要特点是:

参数从右向左传递,并放置在堆栈中。

堆栈清理由调用者执行。

函数名以下划线"_"作为前缀进行修饰。

(来源:call conventions demyfied)(来源:MSDN上的__cdecl)

它说"参数从右到左传递,并放在堆栈上"。这是否意味着函数调用中最右边/最后一个参数总是首先求值?然后倒数第二等等?调用约定__stdcall也是如此,它还指定了从右到左的参数传递顺序。

与此同时,我看到了这样的帖子:

如何在函数调用中求值参数?

在那篇文章中,答案说(他们引用了标准)顺序未指定。

最后,当Charles Petzold写

TextOut(hdc, x, y, szBuffer, snprintf(szBuffer, 64, "My text goes here"));

也许这并不重要?因为即使

szBuffer

之前求值
snprintf(szBuffer, 64, "My text goes here")

函数TextOut是用char*来调用的(指向szBuffer中的第一个字符),由于所有参数都在TextOut函数执行之前求值,因此在这种特殊情况下,先求值哪个并不重要。

在这种情况下不重要

通过将szBuffer传递给接受char *(或char const *)参数的函数,数组衰减为指针。指针值独立于数组中存储的实际数据,无论TextOut()的第四个或第五个参数首先得到完全求值,指针值在这两种情况下都是相同的。即使第四个实参首先被完全求值,它也会作为一个指向数据的指针求值——被改变的是指向数据的,而不是指针本身。

回答你提出的问题:实参求值的实际顺序未指定。例如,在语句f(g(), h())中,兼容的编译器可以以任何顺序执行g()h()。此外,在语句f(g(h()), i())中,编译器可以按任意顺序执行ghi这三个函数,但必须约束h()g()之前执行——因此它可以执行h(),然后执行i(),然后执行g()

在这个特定的情况下,参数的求值顺序是完全无关的。

(这些行为都不依赖于调用约定,它只处理如何将参数传递给被调用函数。调用约定不以任何方式处理这些参数的求值顺序。

我同意这取决于调用约定,因为标准没有指定顺序。参见:c++中的编译器和求值参数顺序

,我也同意,这并不重要,在这种情况下,因为snprintf总是评估之前的TextOut -和缓冲区被填满。