C中的“无效”

时间:2015-02-03 19:17:52

标签: c cc minix

我在更大的C程序中有以下代码。刚才我尝试编译时没有任何问题;它在Minix 2.0.4中运行并使用cc进行编译。编译错误如下所示:

line 26: void not expected

第26行只是main()中的函数声明:

void initpool(void);

initpool()本身稍后会在程序中使用此标头定义:

void
initpool(void)
{

根据我的研究,一切都应该是正确的,gcc不会引发编译错误。之前的所有行都以; s结束,因此不是问题所在。为什么cc在编译时遇到问题?

编辑:根据要求,第26行的行如下(从main()开始,第25行为空白):

19: int
20: main(int argc, char *argv[])
21: {
22:     int count, inserror;
23:     olnode *list, *ptr;
24:     list = NULL;

2 个答案:

答案 0 :(得分:6)

您的计划很可能如下所示:

int main(int argc, char ** argv) {
  ... // (a)
  void initpool(void);
  ...
  initpool();
  ...
}

用(a)表示的部分必须包含一些非声明性陈述。在较旧的C编译器中,在第一个非声明语句之后不允许声明:

void foo() {
  int a;
  int b;
  foo();
  int c; // not allowed in old C
}

因此,有两种可能的解决方法:

// the preferred fix for a single file
void initpool(void);
int main(int argc, char ** argv) {
  ... // (a)
  ...
  initpool();
  ...
}
void initpool(void) {}

// the technically correct fix
int main(int argc, char ** argv) {
  void initpool(void);
  ... // (a)
  ...
  initpool();
  ...
}

initpool的前向声明实际上并不属于main。为什么?因为你应该让编译器帮助你,你不应该重复自己。

就冗长而言,本地声明看起来完全是愚蠢的:

// Good                          // Correct but Verbose
void initpool(void);             void fun1(void) {
void fun1(void) {                  void initpool(void);
  initpool();                      initpool();
}                                }
void fun2(void) {                void fun2(void) {
  initpool();                      void initpool(void);
}                                  initpool();
                                 }

最后,假设initpool()在单独的文件中实现。然后,你可以自由地做任何你想要的愚蠢。例如:

// pool.c
void initpool(void) {
  ...
}
// main.c
int main() {
  void initpool(); // a common typo
  initpool(0);     // undefined behavior, your hard drive gets formatted
}

您应该将池组件的公共API放在单独的头文件中:

/// pool.h
void initpool(void);

/// pool.c
#include "pool.h"
void initpool(void) { ... }

/// main.c
#include "pool.h"
int main() {
  initpool();  // OK
  initpool(0); // the compiler will catch the mistake
}

不要紧,旧的编译器会很乐意接受,例如:

void fun1() {
  void initpool(int);
}
void fun2() {
  void initpool(void);
}

最后,必须说C和C中的(不是C ++),以下声明是兼容的,但这并不能使其安全。行为是实现定义的。例如,这种邋iness会产生无效的stdcall汇编。

void bar();    // an unknown, fixed number of arguments
void bar(int,int,int,int);

如果C允许,void bar()类似于void bar(...)。一些旧的C编译器确实允许省略而没有前面的参数。

感谢Keith Thompson强迫我深入了解事物,并意识到我使用的编译器有多糟糕:)

答案 1 :(得分:3)

在您的问题中汇总代码片段,您有以下内容:

int
main(int argc, char *argv[])
{  
    int count, inserror;
    olnode *list, *ptr;
    list = NULL;

    void initpool(void);  /* line 26 */

    /* ... */
}

在1999年ISO C标准之前,C不允许在一个区块内混合声明和陈述。每个块(包括函数定义的外部块)必须包含零个或多个声明,后跟零个或多个语句

1999标准放宽了这条规则(遵循C ++),但许多C编译器默认仍然执行C90规则。 (C90有时被错误地称为" ANSI C"。)

你有一个声明:

list = NULL;

接着是声明:

void initpool(void);

在声明上方移动声明应该可以解决问题。使用编译器选项来使用C99或更高版本的标准也应该纠正问题,但这可能不可用,具体取决于您使用的编译器。 gcc有-std=c99-std=gnu99-std=c11-std=gnu11;阅读gcc手册了解详情。我不知道编译器" cc"是;这是许多不同C编译器的通用名称。

顺便说一句,将函数声明放在函数定义中有点不寻常。将所有函数声明放在文件范围或更大的项目中将声明放在由定义了#include文件的.c编辑的头文件中更常见。函数以及包含对它们的调用的任何.c文件。显然,你的导师坚持这种风格。它没有错,只要函数声明和定义出现在同一个源文件中,编译器就会诊断出任何不一致。

如果声明使用空括号,则存在潜在问题:

void initpool();

不幸的是,与以下内容兼容:

void initpool(int n) { /* ... */ }

但这与声明是否在函数体内是一致的,并且通过一直使用原型可以轻松避免它。

对于不带参数的函数,请使用(void),而不是()。你已经使用了正确的原型;继续这样做。