C函数调用参数太少

Joh*_*ger 14 c argument-passing

我正在研究一些遗留的C代码.原始代码是在90年代中期编写的,目标是那个时代的Solaris和Sun的C编译器.当前版本在GCC 4下编译(虽然有许多警告),它似乎有效,但我正在努力整理它 - 我想尽可能多地挤出潜在的错误,因为我确定了可能需要的东西.使其适应64位平台,以及编译器以外的编译器.

我在这方面的主要活动之一是确保所有函数都有完整的原型(许多人都没有),在这种情况下我发现了一些调用函数(以前没有原型)的代码,其参数少于函数定义声明.函数实现确实使用了缺少参数的值.

例:

impl.c:

int foo(int one, int two) {
  if (two) {
      return one;
  } else {
      return one + 1;
  }
}
Run Code Online (Sandbox Code Playgroud)

client1.c:

extern foo();
int bar() {
  /* only one argument(!): */
  return foo(42);
}
Run Code Online (Sandbox Code Playgroud)

client2.c:

extern int foo();
int (*foop)() = foo;
int baz() {
  /* calls the same function as does bar(), but with two arguments: */
  return (*foop)(17, 23);
}
Run Code Online (Sandbox Code Playgroud)

问题:是否定义了缺少参数的函数调用的结果?如果是这样,函数将为未指定的参数接收什么值?否则,Sun C编译器的ca. 1996年(对于Solaris,而不是VMS)展示了一种可预测的特定于实现的行为,我可以通过向受影响的调用添加特定的参数值来模拟这种行为吗?

Jim*_*mbo 5

编辑:我发现了一个没有参数行为的堆栈线程C函数,它提供了一个非常简洁和具体,准确的答案.PMG在答案结尾处的评论是关于UB的.以下是我最初的想法,我认为这些想法是相同的,并解释了为什么行为是UB ..

问题:是否定义了缺少参数的函数调用的结果?

我会说不......原因在于我认为该函数将作为第二个参数运行,但如下所述,第二个参数可能只是垃圾.

如果是这样,函数将为未指定的参数接收什么值?

我认为收到的价值是不确定的.这就是你可以拥有UB的原因.

我知道有两种通用的参数传递方式......(维基百科有一个关于调用约定的好页面)

  1. 通过注册.即,平台形式的ABI(应用程序二进制接口)将说明寄存器x和y例如用于传入参数,以及通过堆栈传递的任何更多...
  2. 一切都通过堆栈传递......

因此,当你给一个模块定义一个带有"......未指定(但不是可变的)参数数量......"(extern def)的函数时,它不会放置你给它的那么多参数(在这种情况下) 1)在实际函数将查找的寄存器或堆栈位置中获取参数值.因此,错过的第二个参数的第二个区域基本上包含随机垃圾.

编辑:基于我发现的其他堆栈线程,我会推荐上面说的extern声明一个没有参数的函数来声明一个带有"未指定(但不是可变)参数数量的函数".

当程序跳转到该函数时,该函数假定已正确遵循参数传递机制,因此要么在寄存器或堆栈中查找并使用它找到的任何值...将它们设置为正确.

否则,Sun C编译器的ca. 1996年(对于Solaris,而不是VMS)展示了>>可预测的特定于实现的行为

您必须检查编译器文档.我怀疑它... extern定义将完全被信任所以我怀疑寄存器或堆栈,取决于参数传递机制,将被正确初始化...