Search code examples
cccminix

"void not expected" in C


I have the below code in a larger C program. I've had no issues until just now when I tried to compile it; it's being run in Minix 2.0.4 and compiled using cc. A compilation error is thrown as follows:

line 26: void not expected

Line 26 is simply a function declaration inside main():

void initpool(void);

initpool() itself is defined later in the program with this header:

void
initpool(void)
{

From what I've researched everything should be correct, and gcc throws no compilation errors. All previous lines do end with ;s as they should, so that's not the issue. Why is cc having a problem compiling it?

EDIT: As requested, the lines leading up to line 26 are as follows (starting at the beginning of main(), line 25 is blank):

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

Solution

  • 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 :)