在 C 语言中,调用者是否曾经特别对待可变参数?
In C, does a caller ever treat variadics specially?
据我了解,C 可变参数完全在被调用方处理,即如果您使用
调用函数 f
f(1, 2, 3.0)
无论您是否将 f
声明为
,编译器都会为调用生成相同的代码
void f(int, int, double);
或
void f(int, int, ...);
这个问题的背景是 this issue 从具有可变 FFI 定义的 Rust 调用一个非真正可变的 C 函数。如果从调用者的角度来看可变参数无关紧要(当然除了类型检查),那么我觉得 Rust 会为函数被声明为可变参数的调用生成不同的代码似乎很奇怪。
如果这实际上不是由 C 规范决定的,而是依赖于 ABI,我最感兴趣的是 System V ABI 的答案,从我读到的内容来看,这似乎不是指示调用方对可变参数的任何特殊处理。
这是一个 non-ABI-specific 的回答。
是的,调用者可以(并且在一般情况下将会)以特殊方式处理带有可变参数的函数。这实际上就是为什么从标准化时代开始,C 语言就要求所有可变参数函数在调用点之前 以原型 声明。请注意,即使可以安全地调用 C89/90 中未声明的函数,这样做的权限也不会扩展到可变参数函数:那些总是必须提前声明的。否则,行为未定义。
以稍微不同的形式,规则仍然适用于现代 C。即使 post-C99 C 不再允许调用未声明的函数,它仍然不需要 prototype 声明。然而,可变参数函数必须在调用点之前 使用原型 声明。基本原理是一样的:调用者必须知道它正在调用可变参数函数,并且可能以不同方式处理调用。
从历史上看,有些实现在调用可变参数函数时使用完全不同的调用约定。
据我了解,C 可变参数完全在被调用方处理,即如果您使用
调用函数f
f(1, 2, 3.0)
无论您是否将 f
声明为
void f(int, int, double);
或
void f(int, int, ...);
这个问题的背景是 this issue 从具有可变 FFI 定义的 Rust 调用一个非真正可变的 C 函数。如果从调用者的角度来看可变参数无关紧要(当然除了类型检查),那么我觉得 Rust 会为函数被声明为可变参数的调用生成不同的代码似乎很奇怪。
如果这实际上不是由 C 规范决定的,而是依赖于 ABI,我最感兴趣的是 System V ABI 的答案,从我读到的内容来看,这似乎不是指示调用方对可变参数的任何特殊处理。
这是一个 non-ABI-specific 的回答。
是的,调用者可以(并且在一般情况下将会)以特殊方式处理带有可变参数的函数。这实际上就是为什么从标准化时代开始,C 语言就要求所有可变参数函数在调用点之前 以原型 声明。请注意,即使可以安全地调用 C89/90 中未声明的函数,这样做的权限也不会扩展到可变参数函数:那些总是必须提前声明的。否则,行为未定义。
以稍微不同的形式,规则仍然适用于现代 C。即使 post-C99 C 不再允许调用未声明的函数,它仍然不需要 prototype 声明。然而,可变参数函数必须在调用点之前 使用原型 声明。基本原理是一样的:调用者必须知道它正在调用可变参数函数,并且可能以不同方式处理调用。
从历史上看,有些实现在调用可变参数函数时使用完全不同的调用约定。