函数参数求值顺序
Function argument evaluation order
我对调用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())
中,编译器可以按任意顺序执行g
、h
和i
这三个函数,但必须约束h()
在g()
之前执行——因此它可以执行h()
,然后执行i()
,然后执行g()
。
在这个特定的情况下,参数的求值顺序是完全无关的。
(这些行为都不依赖于调用约定,它只处理如何将参数传递给被调用函数。调用约定不以任何方式处理这些参数的求值顺序。
我同意这取决于调用约定,因为标准没有指定顺序。参见:c++中的编译器和求值参数顺序
,我也同意,这并不重要,在这种情况下,因为snprintf总是评估之前的TextOut -和缓冲区被填满。
- 函数调用中参数的顺序重要吗
- C++部分概念 id:显式模板规范顺序/第一个参数的特殊状态的原因是什么?
- lambda 作为接受其他参数的参数的初始化顺序
- 运算符 new 的执行顺序和构造函数的参数
- 如何检查参数包是否具有执行顺序中的确切类型
- std::bind() 参数列表中函子的执行顺序(可能与函数参数的求值顺序无关)
- 构造函数中没有参数的对象类成员按什么顺序初始化?
- 如何实现对参数顺序不可知的std::same_as的广义形式(即对于两个以上的类型参数)
- 用作成员构造函数参数的函数的求值顺序
- C++17的可选和可变顺序函数参数
- 委派的 ctor 是否受参数计算顺序的影响?
- x64 函数调用参数推送/移动顺序 (MSVC)
- 函数参数计算顺序与 Lambda 捕获评估顺序
- 反转模板(整数)参数的顺序
- 大括号和括号之间的参数计算顺序
- 约束模板参数顺序的更简单方法
- C++ 更改基于参数设置的默认顺序
- 重载运算符以允许C++中参数的不同顺序
- 正确对齐内存模板,参数顺序不变
- 为具有默认值的非顺序参数函数创建启动器