【发布时间】:2015-07-13 19:48:08
【问题描述】:
我对调用 C++ 函数时函数参数的评估顺序感到困惑。我可能解释错了,如果是这样,请解释一下。
例如,Charles Petzold 的传奇著作《Programming 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 调用约定的主要特点是:
参数从右到左传递,并放在堆栈上。
堆栈清理由调用者执行。
函数名的前缀是下划线'_'。
(来源:Calling conventions demystified) (来源:MSDN on __cdecl)
它说“参数从右到左传递,并放在堆栈上”。 这是否意味着函数调用中最右边/最后一个参数总是首先被评估?然后倒数第二个等?调用约定 __stdcall 也是如此,它还指定了从右到左的参数传递顺序。
同时,我遇到了这样的帖子:
How are arguments evaluated in a function call?
在那篇文章中,答案说(并且他们引用了标准)未指定顺序。
最后,查尔斯·佩佐德写道
TextOut(hdc, x, y, szBuffer, snprintf(szBuffer, 64, "My text goes here"));
也许没关系?因为即使
szBuffer
在之前评估
snprintf(szBuffer, 64, "My text goes here")
函数 TextOut 使用 char* 调用(指向 szBuffer 中的第一个字符),并且由于在 TextOut 函数继续执行之前评估所有参数,因此在这种特殊情况下首先评估它并不重要。
【问题讨论】:
-
C 和 C++ 是不同的语言。如果您有兴趣获得两者的答案,您应该在问题中明确提及它们。就目前而言,您只是在询问 C++。
-
“参数从右到左传递,并入栈”:想想“传递”和“求值”的区别。您可能想阅读唯一的权威来源:standard - 好吧,它是最终草案,但这没有什么区别。一个好的 serach-term 将是 sequence points
-
如你所说,在这种情况下没关系,因为参数 szBuffer 只是一个指针。即使稍后将评估 snprintf 表达式,此指针也不会更改。只是 szBuffer 指向的缓冲区确实发生了变化。
-
感谢您的 cmets,我明白我的困惑归结为区分“通过”和“评估”。评估顺序:未指定,参数传递顺序:从右到左。
-
@jensa 参数传递顺序不一定从右到左。在带有 cdecl 的 32 位 Windows 上是的。在 64 位 Windows 上,调用约定是基于寄存器的约定。
标签: c++ winapi argument-passing calling-convention