旧式C函数声明

Oxd*_*eef 16 c coding-style runtime function

这是一个简单的函数delcared并使用旧样式语法定义:

#include <stdio.h>
void
error(message,a1,a2,a3,a4,a5,a6,a7)
        char *message;
        char *a1,*a2,*a3,*a4,*a5,*a6,*a7;
{
  fprintf(stderr,message,a1,a2,a3,a4,a5,a6,a7);
}
int main ()
{
  error("[ERROR %d]: %s.\n",110,"Connection timed out");
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

它可以编译并正确运行以进行打印:

[ERROR 110]:连接超时.

我读到这个样式没有相关的原型,但是如何在运行时自动将int转换为char*,甚至提供的参数少于声明的参数?

Cha*_*tin 17

基本上,它的工作原理是因为它太愚蠢而无法更好地了解.老式的K&R C基本上不检查任何东西.你逃避了,因为,

  1. 它发生sizeof(int) == sizeof(char *)在您正在使用的特定体系结构和编译器组合上.它并没有真正转换任何东西,只是数字32位是32位.

  2. 当你把所有这些参数放在堆栈上时,它只是将它们推入.当printf使用它们时,它只是在需要时使用它们而剩下的就是其余部分; 然后,当呼叫返回时,它们就会消失,而且没有人会更聪明.但是,如果你碰巧尝试打印七个值,你只传递六个参数,它会在运行时爆炸,有时会以创造性和意想不到的方式爆炸.

  • @Ox,但`char`在函数参数中变成`int`,因为默认参数提升(§6.5.2.2/ 6),包括整数提升(§6.3.1.1/ 2). (2认同)
  • 牛,你不是在仔细阅读 - 我说的是sizeof(int)== sizeof(CHAR STAR),即指向char的指针的大小.马修,你对促销是正确的,但请注意,参数是指向char的指针,而不是char. (2认同)

Mat*_*hen 9

传递太少的参数或错误的类型(您已经完成了两者)会导致未定义的行为.这正是您不应该在新代码中使用旧样式语法的原因.如果您使用了新语法,您将从函数定义中获得"免费"原型.换一种说法:

void
error(char * message,
char * a1, char * a2, char * a3, char * a4, char * a5, char * a6, char * a7)
{

}
Run Code Online (Sandbox Code Playgroud)

也是一个原型.

使用旧语法,您必须提供自己的语法,而不是.这意味着编译器无法检查调用.

在实践中(在你的机器上),error正在int从堆栈中读取到char *.然后,它传递char *fprintf.但是使用了一个%d说明符,所以将其fprintf弹出为int.这是未定义的行为.但它碰巧适用于您的机器; char *并且int可能大小相同.

error还会从char *堆栈中读取5个垃圾值.然后它将这些传递给fprintf它,它忽略了,因为只有两个转换说明符.