我记得,早期的C(例如K&R)允许在任何函数调用上传递任何内容,因此调用约定必须是将args从右推到左,并且调用方在函数返回后清除堆栈。
我在演示中遇到了一个难题,解决方案包括调用printf而根本不使用任何头文件。他断言,在C中,如果调用一个未声明的函数,则编译器将其参数列表隐式地接受为它所传递的提升参数。
但是,在ANSI C的斜坡上引入的新的启用原型的函数调用使用了一个更高效的调用约定,即被调用的函数清除堆栈;它不会被每次使用重复。
在我的回忆中,这两种形式被赋予不同的链接器-可见的名称,并且不兼容,这是在链接时间捕捉到的。我坚持认为,他的例子起了作用,因为printf故意使用旧的表单,使任何和任何东西都可以在逐调用的基础上传递。
他说,这两种用途必须兼容,这是标准规定的。除非编译器总是生成旧风格的调用,否则我看不出它是如何工作的。
根据标准,实际情况是什么?而且,这是什么历史-它是否随着时间的推移而改变?
发布于 2018-06-12 00:16:57
C标准对调用约定没有任何规定。
从1989年的ANSI标准(相当于1990年的ISO标准)开始,在没有正确的范围声明的情况下调用像printf这样的变量函数具有未定义的行为。该声明必须是一个原型,并且它必须包含, ...序列,以指示接受变量数和参数类型。
从1999年的ISO C标准开始,调用没有可见声明的函数是一种违反约束的行为,需要进行诊断。(这几乎等于说一个构造是非法的。)在C99之前,调用的函数将使用int的返回类型隐式声明,并在调用中显示任何(提升的)参数。
许多C编译器将接受(可能带有警告)没有声明的调用,而许多编译器可能使用调用约定来调用printf,而没有明显的声明“工作”。但是语言并没有定义这样一个调用的行为,一个符合规范的编译器可以自由地拒绝它,或者生成任意错误行为的代码。
如果要调用printf,只需在源文件的顶部添加#include <stdio.h>即可。这比考虑在给定的编译器中可以逃脱的问题要容易得多。
https://stackoverflow.com/questions/50807627
复制相似问题