我记得,早期的C(例如K& R)允许在任何函数调用上传递任何东西,因此调用约定必须是从右向左推动args并且调用者在清除堆栈之后清除堆栈。函数返回。
我在演示文稿中遇到了一个难题,解决方案涉及调用printf
而根本不使用任何头文件。他断言在C中如果你调用一个尚未声明的函数,那么编译器会隐式地将其参数列表作为它看到你传递的提升参数。
但是,在升级到ANSI C时引入的新的启用原型的函数调用使用了更高效的调用约定,其中被调用函数清除堆栈;每次使用都不会重复。
在我的回忆中,这两个表单被赋予了不同的链接器可见名称,并且不兼容,这是在链接时捕获的。我坚持认为,他的例子很有效,因为printf
有目的地使用旧形式,以便能够在逐个呼叫的基础上传递任何和任何事物。
他说这两个用途必须兼容,由标准规定。除非编译器总是生成旧式调用,否则我看不出它是如何工作的。
根据标准的实际情况是什么?而且,历史是什么 - 它随着时间的推移而改变了吗?
答案 0 :(得分:4)
C标准对调用约定一无所知。
从1989 ANSI C标准(相当于1990 ISO C标准)开始,在范围内调用类似printf
的可变参数函数而没有正确的声明具有未定义的行为。该声明必须是原型,并且必须包含, ...
序列,以指示接受变量数量和参数类型。
从1999 ISO C标准开始,调用没有可见声明的函数是约束违规,需要诊断。 (这与C一样接近说构造是非法的。)在C99之前,调用函数将被隐式声明,返回类型为int
,并且调用中出现任何(提升的)参数。 / p>
许多C编译器接受(可能带有警告)没有声明的调用,并且很多可能使用调用约定来调用printf
而没有可见的声明" work"。但是语言没有定义这种调用的行为,并且符合标准的编译器可以自由地拒绝它或生成任意行为不当的代码。
如果您想致电printf
,只需在源文件的顶部添加#include <stdio.h>
即可。这比考虑给定编译器可以逃脱的内容要容易得多。