69 c function kernighan-and-ritchie function-declaration function-definition
这个C语法有什么用- 使用'K&R'样式函数声明?
int func (p, p2)
void* p;
int p2;
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我能够在Visual Studios 2010beta中写这个
// yes, the arguments are flipped
void f()
{
void* v = 0;
func(5, v);
}
Run Code Online (Sandbox Code Playgroud)
我不明白.这种语法有什么意义?我可以写:
int func (p, p2)
int p2;
{
return 0;
}
// and write
int func (p, p2)
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它似乎唯一指定的是它使用了多少参数和返回类型.我猜没有类型的参数有点酷,但为什么允许它和int paranName函数声明后?有点奇怪.
这还是标准的C吗?
AnT*_*AnT 145
你问的问题实际上是两个问题,而不是一个问题.到目前为止,大多数回复试图用一般的毯子覆盖整个事物"这是K&R风格"的答案,而事实上它只有一小部分与所谓的K&R风格有关(除非你看到整个C语言)以某种方式作为"K&R风格":)
第一部分是函数定义中使用的奇怪语法
int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这个实际上是一个K&R风格的函数定义.其他答案已经很好地涵盖了这一点.实际上并没有太多的东西.语法不推荐使用,但即使在C99中仍然完全支持(C99中的"无隐式int"规则除外,这意味着在C99中你不能省略声明p2).
第二部分与K&R风格没什么关系.我指的是可以用"交换"参数调用该函数,即在这样的调用中不进行参数类型检查.这与K&R风格的定义本身没什么关系,但它与你没有原型的功能有关.你看,当你声明这样的函数时,在C中
int foo();
Run Code Online (Sandbox Code Playgroud)
它实际上声明了一个函数foo,它接受未知类型的未指定数量的参数.你可以称之为
foo(2, 3);
Run Code Online (Sandbox Code Playgroud)
并作为
j = foo(p, -3, "hello world");
Run Code Online (Sandbox Code Playgroud)
如此(你明白了);
只有具有适当参数的调用才会"起作用"(意味着其他人产生未定义的行为),但完全取决于您确保其正确性.编译器不需要诊断不正确的编译器,即使它以某种方式神奇地知道正确的参数类型及其总数.
实际上,这种行为是C语言的一个特性.一个危险的,但仍然是一个功能.它允许你做这样的事情
void foo(int i);
void bar(char *a, double b);
void baz(void);
int main()
{
void (*fn[])() = { foo, bar, baz };
fn[0](5);
fn[1]("abc", 1.0);
fn[2]();
}
Run Code Online (Sandbox Code Playgroud)
即在"多态"数组中混合不同的函数类型而不进行任何类型转换(尽管这里不能使用可变函数类型).同样,这种技术的固有危险是非常明显的(我不记得曾经使用它,但我可以想象它可能在哪里有用),但毕竟这是C.
最后,将答案的第二部分链接到第一部分的位.当您进行K&R样式的函数定义时,它不会为函数引入原型.就函数类型而言,您的func定义声明func为
int func();
Run Code Online (Sandbox Code Playgroud)
即既未声明类型也未声明参数总数.在您的原始帖子中,您说"......它似乎指明了它使用了多少个参数......".从形式上讲,它没有!你的两个参数K&R风格后func的定义,你仍然可以调用func如
func(1, 2, 3, 4, "Hi!");
Run Code Online (Sandbox Code Playgroud)
并且不会有任何违反约束的行为.(通常,质量编译器会给你一个警告).
此外,有时被忽视的事实是
int f()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
也是一种K&R风格的函数定义,不会引入原型.要使它"现代",你必须void在参数列表中加上显式
int f(void)
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
最后,与流行的看法相反,C99完全支持K&R风格的函数定义和非原型函数声明.如果我没记错的话,前者自C89/90以来已被弃用.C99要求在第一次使用之前声明函数,但声明不需要是原型.混乱显然源于流行的术语混淆:许多人将任何函数声明称为"原型",而实际上"函数声明"与"原型"不同.
Dir*_*irk 17
这是非常古老的K&R C语法(早于ANSI/ISO C).现在,你不应再使用它了(因为你已经注意到它的主要缺点:编译器不会为你检查参数的类型).参数类型实际上int在您的示例中默认为.
当时,使用了这种语法,人们有时会发现这样的函数
foo(p, q)
{
return q + p;
}
Run Code Online (Sandbox Code Playgroud)
这实际上是一个有效的定义,作为类型foo,p和q默认int.