有关此 C 语法的有用信息—使用'K& R'样式函数声明?

int func (p, p2)
    void* p;
    int  p2;
{
    return 0;
}

我能够在Visual Studios 2010beta中写这个

// 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 paranName ?这很奇怪。

这还是标准C吗?

有帮助吗?

解决方案

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

第一部分是函数 definition

中使用的奇怪语法
int func(p, p2)
void *p;
int  p2; /* <- optional in C89/90, but not in C99 */
{
  return 0;
}

这个实际上是K&amp; R风格的功能定义。其他答案已经很好地涵盖了这一点。实际上并没有太多的东西。不推荐使用该语法,但即使在C99中仍然完全支持该语法(C99中的“无隐式int”规则除外,这意味着在C99中您不能省略 p2 的声明)。

第二部分与K&amp; R风格没什么关系。我指的是可以使用“swapped”调用该函数的事实。参数,即在这样的调用中不进行参数类型检查。这与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要求在第一次使用之前声明函数,但声明不需要是原型。混乱显然源于流行的术语混淆:许多人将任何函数声明称为“原型”,而实际上是“函数声明”。与“原型”不同。

其他提示

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

当时使用了这种语法,有时会找到像

这样的函数
foo(p, q) 
{
    return q + p;
}

实际上是一个有效的定义,因为 foo p q 的类型默认为 int

这只是一种旧语法,它早于“ANSI C”。您可能更熟悉的语法。它通常被称为“ K&amp; RC ”。

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

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

这是C没有功能原型的遗物。当时的方式,(我认为)函数被假定为返回 int ,并且其所有参数都被假定为 int 。没有检查功能参数。

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

C99需要声明函数(可能没有原型)。如果你是从头开始编写一个新函数,你需要提供一个声明......使它成为一个原型:你什么都不会丢失并从编译器中获得额外的检查。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top