函数调用何时复制其相对于参数序列的按值传递参数?

大卫·托特

我想尽可能多地理解这个代码片段,因为未定义的行为允许它:

int i = 0;
printf("%d %d %d", i, ++i, i++);

输出:

2 2 0

据我所知:

  • 逗号,定义了一个序列
  • 当在函数参数调用中计算所有序列时,会发生实际打印
  • 由于参数是按值传递的,因此在调用函数时有时会发生副本(?!)
  • 函数参数序列求值的顺序未定义(这是真的吗?)

因此,据我所知,该单行代码中的大部分行为是未定义的,但我仍然想了解不是未定义行为的部分。我知道输出取决于编译器,但是 C 标准中定义了哪些部分?我也对 ANSI C、C99 感兴趣,但我相信最新的 C++ 标准至少在某些方面对此有所改进,这是真的吗?

伦丁

逗号,定义一个序列

不。不要混淆函数参数列表中的逗号操作符(逗号操作符的作用是什么?)。实际,符号在 C 语法中的许多不同地方使用,但它具有明确定义的求值顺序的唯一地方是当它用于实际的逗号运算符时。函数调用参数列表和初始值设定项列表都没有明确定义的顺序。

C 标准是关于函数调用和参数的(C17 6.5.2.2):

在函数指示符和实际参数的计算之后但在实际调用之前有一个序列点。调用函数(包括其他函数调用)中的每一个在被调用函数体执行之前或之后没有特别排序的评估都相对于被调用函数的执行是不确定的。

在你的情况下,4 个参数"%d %d %d", i, ++i,i++相互之间是不确定的,序列点,如上所述,放在参数评估之后


要解决您的其他陈述:

  • 当在函数参数调用中计算所有序列时,会发生实际打印

    正确,但未定义的行为已经发生。

  • 由于参数是按值传递的,因此在调用函数时有时会发生副本(?!)

    您可以假设这些确实是按值传递的。printf是一个 icky 可变参数函数,所以它们最终在 a 中va_list,我相信它在内部有一个实现定义的表示。

  • 函数参数序列求值的顺序未定义(这是真的吗?)

    函数参数的求值顺序是未指定的行为,这意味着我们无法知道顺序 - 它可能是未记录的 - 因此我们不应该假设特定的顺序。由于 6.5/2,实际的未定义行为发生了:

    如果对标量对象的副作用相对于对同一标量对象的不同副作用或使用同一标量对象的值进行的值计算而言是未排序的,则行为未定义。如果一个表达式的子表达式有多个允许的排序,并且在任何排序中出现这种未排序的副作用,则行为是未定义的。

  • 我想了解不是未定义行为的部分。

    我不确定你的意思,因为代码不能“只是有点未定义”。如果它有未定义的行为,那么关于该程序中的任何内容的所有赌注都将关闭你不能对它进行推理,否则它不会是未定义的,而是别的东西。因此,像“未定义的行为将此值转换为 55 然后按值传递”这样的推理是没有意义的。例如,UB 可能会导致整个函数调用被优化掉或以奇怪的方式内联。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

计算相对于特定值的zscore

Java:何时使方法相对于实例成为静态

函数定义了未命名的参数,但调用者仍传递值

相对于其容器放置元素

按值传递参数时是否保证复制构造函数调用

根据其参数的值类别调用函数

使用inout关键字:是通过引用传递或通过复制输入复制输出的参数(/按值结果调用)

C ++中的函数重载按值或按引用传递参数

如何调用作为参数传递的函数,其参数已在D中给出?

传递任何函数,无论其参数如何

为什么或何时在调用之前将可调用函数参数转换为右值?

函数调用后,参数指针不保留其值

调用函数时按名称反应传递参数

在函数内调用函数并传递其参数(* args)-Python

如果给printf()相对于其各自的格式说明符的参数类型有误,C编译器是否会尝试隐式转换它?

如何在“存储桶”内相对于“按字母顺序”对聚合函数进行排序

构造函数参数的引用成员按值传递

在传递(作为其参数的参数)函数内部使用动态值以供bind方法本身使用

何时使用构造函数以及何时传递参数

MySQL限制参数相对于行值

何时将指针参数传递给函数

函数参数:即使按值传递,原始变量也会被修改

函数如何修改C ++中按值传递的参数?

按值传递参数

通过函数指针传递给可变参数的参数会更改其值

按值调用,并将值解释为零参数函数,按值调用

如何按名称调用函数,作为参数传递?

简单赋值帮助:调用函数向其传递参数并获取其返回值

JFreeChart - 相对于 TimeZone 的时间序列