"void not expected" 在 C 中
"void not expected" in C
我在一个更大的 C 程序中有以下代码。直到刚才我尝试编译它时,我才遇到任何问题;它在 Minix 2.0.4 中是 运行 并使用 cc
编译。抛出编译错误如下:
line 26: void not expected
第26行只是main()
里面的一个函数声明:
void initpool(void);
initpool()
本身稍后在程序中用这个 header:
定义
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;
您的程序很可能如下所示:
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
}
您应该在单独的头文件中包含池组件的 public 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++)中,以下声明是兼容的,但这并不安全。该行为是实现定义的。例如,这种草率会生成无效的 stdcall 程序集。
void bar(); // an unknown, fixed number of arguments
void bar(int,int,int,int);
如果 C 允许,void bar()
类似于 void bar(...)
。一些旧的 C 编译器确实允许没有前面参数的省略号。
感谢 Keith Thompson 迫使我深入研究事物,并意识到我使用的一些编译器有多糟糕:)
将您问题中的代码片段放在一起,您有以下内容:
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 编译器的通用名称。
顺便说一句,将函数声明放在函数定义中有点不寻常。更常见的是将所有函数声明放在文件范围内,或者对于较大的项目将声明放在头文件中,该头文件由定义函数的 .c
文件和任何 .c
编辑] 包含对它们的调用的文件。不过,显然你的导师坚持这种风格。这没有错,只要函数声明和定义出现在同一个源文件中,编译器就会诊断出任何不一致之处。
如果声明使用空括号,则可能存在问题:
void initpool();
不幸的是,兼容:
void initpool(int n) { /* ... */ }
但这与声明是否在函数体内无关,通过始终使用原型很容易避免这种情况。
对于不带参数的函数,请使用 (void)
,而不是 ()
。您已经在使用正确的原型;继续这样做。
我在一个更大的 C 程序中有以下代码。直到刚才我尝试编译它时,我才遇到任何问题;它在 Minix 2.0.4 中是 运行 并使用 cc
编译。抛出编译错误如下:
line 26: void not expected
第26行只是main()
里面的一个函数声明:
void initpool(void);
initpool()
本身稍后在程序中用这个 header:
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;
您的程序很可能如下所示:
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
}
您应该在单独的头文件中包含池组件的 public 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++)中,以下声明是兼容的,但这并不安全。该行为是实现定义的。例如,这种草率会生成无效的 stdcall 程序集。
void bar(); // an unknown, fixed number of arguments
void bar(int,int,int,int);
如果 C 允许,void bar()
类似于 void bar(...)
。一些旧的 C 编译器确实允许没有前面参数的省略号。
感谢 Keith Thompson 迫使我深入研究事物,并意识到我使用的一些编译器有多糟糕:)
将您问题中的代码片段放在一起,您有以下内容:
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 编译器的通用名称。
顺便说一句,将函数声明放在函数定义中有点不寻常。更常见的是将所有函数声明放在文件范围内,或者对于较大的项目将声明放在头文件中,该头文件由定义函数的 .c
文件和任何 .c
编辑] 包含对它们的调用的文件。不过,显然你的导师坚持这种风格。这没有错,只要函数声明和定义出现在同一个源文件中,编译器就会诊断出任何不一致之处。
如果声明使用空括号,则可能存在问题:
void initpool();
不幸的是,兼容:
void initpool(int n) { /* ... */ }
但这与声明是否在函数体内无关,通过始终使用原型很容易避免这种情况。
对于不带参数的函数,请使用 (void)
,而不是 ()
。您已经在使用正确的原型;继续这样做。