3

我在一个更大的 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;
4

2 回答 2

6

Most likely your program looks as follows:

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

The part denoted with (a) must contain some non-declaration statements. In older C compilers, declarations aren't allowed after the first non-declaration statement:

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

So, there are two possible fixes:

// 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();
  ...
}

The initpool's forward declaration really doesn't belong inside main. Why? Because you are supposed to let the compiler help you, and you shouldn't have to repeat yourself.

In terms of verbosity, the local declarations look outright silly:

// 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();
                                 }

Finally, suppose that initpool() is implemented in a separate file. Then you're free to do whatever silliness you desire. For example:

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

You should have the public API of the pool component in a separate header file:

/// 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
}

Never mind that old compilers will gladly accept, for example, this:

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

Finally, it must be said that in C, and only in C (not C++), the following declarations are compatible, but that doesn't make it safe. The behavior is implementation defined. Such sloppiness will generate invalid assembly with stdcall, for example.

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

The void bar() is akin to void bar(...) if C allowed such. Some old C compilers do indeed allow ellipsis without a preceding argument.

Thanks to Keith Thompson for forcing me to look deeper into things, and realizing how bad some compilers I use are :)

于 2015-02-03T19:22:53.987 回答
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),而不是()。您已经在使用正确的原型;继续这样做。

于 2015-02-03T20:10:51.103 回答