Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
函数声明与原型的可选(K&R)C语法_C_Function_Function Declaration_Kernighan And Ritchie_Function Definition - Fatal编程技术网

函数声明与原型的可选(K&R)C语法

函数声明与原型的可选(K&R)C语法,c,function,function-declaration,kernighan-and-ritchie,function-definition,C,Function,Function Declaration,Kernighan And Ritchie,Function Definition,这个C语法有什么有用之处-使用“K&R”风格的函数声明 int func (p, p2) void* p; int p2; { return 0; } 我能在2010年Beta版的Visual Studio中写这篇文章 // yes, the arguments are flipped void f() { void* v = 0; func(5, v); } 我不明白。这种语法有什么意义?我可以写: int func (p, p2) int

这个
C
语法有什么有用之处-使用“K&R”风格的函数声明

int func (p, p2)
    void* p;
    int  p2;
{
    return 0;
}
我能在2010年Beta版的Visual Studio中写这篇文章

// yes, the arguments 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-name
?真奇怪


这仍然是标准的C吗?

这只是一种旧语法,它早于您可能更熟悉的“ANSIC”语法。它通常被称为“”


编译器支持它的完整性,当然也支持它能够处理旧的代码库。

这是非常古老的K&R C语法(早于ANSI/ISO C)。现在,您不应该再使用它了(因为您已经注意到它的主要缺点:编译器不会为您检查参数类型)。在您的示例中,参数类型实际上默认为
int

当时,使用这种语法时,有时会发现如下函数

foo(p, q) 
{
    return q + p;
}

这实际上是一个有效的定义,因为
foo
p
q
的类型默认为
int
,这是C没有函数原型时的遗留。当时,(我认为)函数被假定为返回
int
,它的所有参数都被假定为
int
。没有对函数参数进行检查

在当前的C语言中使用函数原型会更好。
您必须在C99中使用它们(C89仍然接受旧语法)


C99需要声明函数(可能没有原型)。如果您从头开始编写新函数,则需要提供声明。。。把它也做成一个原型:你不会丢失任何东西,并从编译器那里获得额外的检查。

这是C在1989年标准化之前的原始K&R语法。C89引入了函数原型,从C++中借用,并禁止了K&R语法。在新代码中没有理由使用它(也有很多理由不使用)。

您要问的问题实际上是两个问题,而不是一个。到目前为止,大多数回复都试图用一个通用的“这是K&R风格”的答案来覆盖整个问题,而实际上只有一小部分与所谓的K&R风格有关(除非您以某种方式将整个C语言视为“K&R风格”)

第一部分是函数定义中使用的奇怪语法

它实际上声明了一个函数
foo
,该函数接受未知类型的未指定数量的参数。你可以称之为

foo(2, 3);
作为

j = foo(p, -3, "hello world");
等等(你明白了)

只有带有正确参数的调用才会“起作用”(意味着其他调用会产生未定义的行为),但确保其正确性完全取决于您。编译器不需要诊断错误的参数,即使它神奇地知道正确的参数类型及其总数

实际上,这种行为是C语言的一个特点。一个危险的,但仍然是一个特点。它允许你做这样的事情

int foo();
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]();
}
i、 e.在一个“多态”数组中混合不同的函数类型,而不使用任何类型转换(虽然这里不能使用可变函数类型)。同样,这种技术的固有危险是非常明显的(我不记得曾经使用过它,但我可以想象它在哪里有用),但这毕竟是C

最后,将答案的第二部分链接到第一部分的位。当您创建K&R风格的函数定义时,它不会为函数引入原型。就函数类型而言,您的
func
定义将
func
声明为

int func();
func(1, 2, 3, 4, "Hi!");
i、 e.既不声明类型,也不声明参数总数。在你原来的帖子中,你说“…它似乎指定了它使用了多少个参数…”。从形式上讲,它不是!在定义了两个参数K&R-style
func
之后,仍然可以按如下方式调用
func

int func();
func(1, 2, 3, 4, "Hi!");
而且不会有任何违反约束的情况。(通常,高质量的编译器会给您一个警告)

此外,一个有时被忽视的事实是

int f()
{
  return 0;
}
也是一个K&R风格的函数定义,不引入原型。要使其“现代化”,您必须在参数列表中添加一个显式的
void

int f(void)
{
  return 0;
}

最后,与流行的观点相反,C99完全支持K&R风格的函数定义和非原型函数声明。如果我没记错的话,前者从C89/90开始就被弃用了。C99要求在首次使用之前声明函数,但不要求声明为原型。这种混淆显然源于流行的术语混淆:许多人将任何函数声明称为“原型”,而实际上“函数声明”与“原型”并不相同。

不正确。在C99中,函数在调用之前必须显式声明。然而,C99不需要prorotyped声明。C99完全支持K&R语法,但有一个改动:隐式
int
规则已被删除。但是varargs函数和非类型化函数之间的区别是什么。@Sebastian Godelet varargs不必要地严格。例如,使用一个int调用vararg函数,并将其作为字节弹出是无效的。定义一个只有vararg参数的函数也是如此。@Sebastian vararg函数实际上可以用不同数量的参数正确调用,例如
printf
。没有原型的函数只能使用固定数量的参数才能正确调用,但编译器不知道是哪一个参数,也无法检查(因此您必须这样做)。我想是时候更改C99中支持的
<代码>C99到C11
:-)。我记得当我在Amstrad PCW上开始使用C时