函数参数评估顺序

Function argument evaluation order

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

例如,Charles Petzold 的传奇著作“编程 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")

其中returns写入char[] szBuffer的字符数。它还将文本“My text goes here”写入 char[] szBuffer。 第四个参数是 szBuffer,它包含要写入的文本。然而,我们可以看到 szBuffer 填充在第五个参数中,告诉我们不知何故是表达式

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

之前评估过

// argument 4
szBuffer

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

The main characteristics of __cdecl calling convention are:

Arguments are passed from right to left, and placed on the stack.

Stack cleanup is performed by the caller.

Function name is decorated by prefixing it with an underscore character '_' .

(来源:Calling conventions demystified) (来源:MSDN on __cdecl

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

同时,我遇到了post这样的:

How are arguments evaluated in a function call?

其中 post 答案说(并且他们引用了标准)订单未指定。

最后,当 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() 的第四个或第五个参数是否得到,指针值 在这两种情况下都是相同的 首先进行全面评估。即使第 4 个参数首先被完全求值,它也会作为指向数据的指针求值——指向的数据被改变,而不是指针本身。

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

碰巧在这种特定情况下,参数的评估顺序完全无关紧要。

(此行为的None 取决于调用约定,它只处理参数如何传递给被调用函数。调用约定不以任何方式解决这些参数的顺序评价。)

我同意这取决于调用约定,因为标准没有指定顺序。 另见:Compilers and argument order of evaluation in C++

而且我也同意在这种情况下无关紧要,因为 snprintf 总是在 TextOut 之前求值 - 并且缓冲区被填满。