这个C
语法的用处是什么 - 使用'K& R'样式函数声明?
int func (p, p2)
void *p;
int p2;
{
return 0;
}
我能够在Visual Studios 2010beta中写这个
//yes the params are flipped
void f()
{
void *v=0;
func(5,v);
}
我不明白。这种语法有什么意义?我可以写:
int func (p, p2)
int p2;
{
return 0;
}
//and write
int func (p, p2)
{
return 0;
}
它似乎唯一指定的是它使用了多少参数和返回类型。我想没有类型的参数有点酷,但为什么允许它和函数声明符之后的int paranName
?这很奇怪。
这还是标准C吗?
答案 0 :(得分:141)
你问的问题实际上是两个问题,而不是一个问题。到目前为止,大多数回复试图用一般的毯子覆盖整个事物“这是K& R风格”的答案,而事实上它只有一小部分与所谓的K& R风格有关(除非你看到整个C语言以某种方式作为“K& R-style”:)
第一部分是函数 definition
中使用的奇怪语法int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
这个实际上是K&amp; R风格的功能定义。其他答案已经很好地涵盖了这一点。实际上并没有太多的东西。语法已弃用,但即使在C99中仍然完全支持(C99中的“无隐式整数”规则除外,这意味着在C99中您不能省略p2
的声明。)
第二部分与K&amp; R风格没什么关系。我指的是可以用“交换”参数调用该函数,即在这样的调用中不进行参数类型检查。这与K&amp; R风格的定义本身几乎没什么关系,但它与你没有原型的功能有关。当你声明一个像这样的函数时,你会看到在C中
int foo();
它实际上声明了一个函数foo
,该函数带有未知类型的未指定数量的参数。您可以将其称为
foo(2, 3);
和
j = foo(p, -3, "hello world");
如此(你明白了);
只有具有适当参数的调用才会“起作用”(意味着其他人产生未定义的行为),但完全取决于您确保其正确性。即使编译器以某种方式神奇地知道正确的参数类型及其总数,编译器也不需要诊断错误的编译器。
实际上,此行为是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]();
}
即。在不使用任何类型转换的“多态”数组中混合不同的函数类型(虽然这里不能使用可变参数函数类型)。同样,这种技术的固有危险是非常明显的(我不记得曾经使用它,但我可以想象它在哪里有用),但毕竟这是C.
最后,将答案的第二部分链接到第一部分的位。当您制作K&amp; R风格的函数定义时,它不会为函数引入原型。就功能类型而言,您的func
定义将func
声明为
int func();
即。既未声明类型也未声明参数总数。在您的原始帖子中,您说“......它似乎指明了它使用了多少个参数......”。从形式上讲,它没有!在您的双参数K&amp; R风格func
定义后,您仍然可以将func
称为
func(1, 2, 3, 4, "Hi!");
并且不会有任何约束违规。 (通常,质量编译器会给你一个警告)。
此外,有时被忽视的事实是
int f()
{
return 0;
}
也是K&amp; R风格的函数定义,不引入原型。要使其“现代化”,您必须在参数列表
中加上明确的void
int f(void)
{
return 0;
}
最后,与流行的看法相反,C99完全支持K&amp; R风格的函数定义和非原型函数声明。如果我没记错的话,前者自C89 / 90以来就被弃用了。 C99要求在第一次使用之前声明函数,但声明不需要是原型。混乱显然源于流行的术语混淆:许多人将任何函数声明称为“原型”,而实际上“函数声明”与“原型”不同。
答案 1 :(得分:17)
这是非常古老的K&amp; R C语法(早于ANSI / ISO C)。现在,你不应再使用它了(因为你已经注意到它的主要缺点:编译器不会为你检查参数的类型)。在您的示例中,参数类型实际默认为int
。
当时使用了这种语法,有时会找到像
这样的函数foo(p, q)
{
return q + p;
}
实际上是一个有效的定义,因为foo
,p
和q
的类型默认为int
。
答案 2 :(得分:4)
这只是一种旧语法,它可以提供您可能更熟悉的“ANSI C”语法。它通常被称为“K&R C”。
编译器支持它完整,当然也能够处理旧的代码库。
答案 3 :(得分:1)
这是C没有功能原型的遗物。当时的方式,(我认为)函数被假定为返回int
,并且其所有参数都被假定为int
。没有检查功能参数。
在当前的C语言中使用函数原型会好得多。
你必须在C99中使用它们(C89仍然接受旧的语法)。
C99需要声明函数(可能没有原型)。如果你是从头开始编写一个新函数,你需要提供一个声明......使它成为一个原型:你什么都不会丢失并从编译器中获得额外的检查。
答案 4 :(得分:1)
这是1989年C标准化之前的原始K&amp; R语法.C89引入了函数原型,借用了C ++,并弃用了K&amp; R语法。在新代码中没有理由使用它(并且有很多理由)。
答案 5 :(得分:-1)