G++ error: ‘<anonymous>’ has incomplete type

余生长醉 提交于 2019-12-05 08:05:20
Keith Thompson

Quick summary: The code is not valid C++, though there's some lack of clarity about whether it should be. Using void rather than VOID, or just using empty parentheses, will avoid the error.

I think this is a bug in g++.

I thought this was a bug in g++. I'm now convinced that it isn't, though I argue that it would be better to make this a warning rather than a fatal error.

Normally in C++, a function with no parameters is declared with empty parentheses:

int foo();

As a concession to C compatibility, C++ also allows a C-style prototype, using void to indicate that the function has no parameters (since empty parentheses mean something else in C):

int bar(void);

g++'s interpretation seems to be that the void in this syntax here doesn't refer to the incomplete type void; rather, it treats it as a special syntax with a distinct use of the keyword.

I think you'll need to modify the header file to get g++ to accept it.

gcc accepts it as valid C, but that's not helpful if you need to #include it from a C++ source file -- unless you write a C wrapper and invoke it from your C++ code, which might be an acceptable workaround.

(Incidentally, I hate typedefs like that. What's the purpose of typedef void VOID;? Did the author think void was too confusing? I suspect it's for compatibility with very old C compilers that didn't support the void keyword, but the need for that is long past.)

Here's the relevant description from the latest draft of the ISO C++ 2011 standard (8.3.5 [dcl.fct]):

The parameter-declaration-clause determines the arguments that can be specified, and their processing, when the function is called. [ ... ] If the parameter-declaration-clause is empty, the function takes no arguments. The parameter list (void) is equivalent to the empty parameter list. Except for this special case, void shall not be a parameter type (though types derived from void, such as void*, can).

This implies that the void keyword in int bar(void); does refer to the type void. Since a typedef name is a synonym for the named type, int bar(VOID); should be equally legal. It would make the most sense for a typedef name like VOID to be accepted in place of void, but the wording of the standard actually refers to the keyword void, not to the type.

The whole purpose of permitting (void) is C compatibility. Just to add to the confusion, the 1990 ISO C standard requires the void keyword; the 1999 and 2011 C standards changed the wording, allowing a typedef instead. The response to C++ Defect Report #577 confirms that the current wording requires the void keyword, and proposes a change that will permit a typedef -- but that change is not yet in any ISO C++ standard. It will probably appear in the first Technical Corrigendum for C++ 2011, whenever it's published.

Thanks to another.anon.coward for finding the existing gcc bug report. I've added an overly verbose comment suggesting that the code is valid and the error message should not be produced -- and a later comment conceding that the code is invalid, but that a warning would be more appropriate than a fatal error.

In the meantime, I suggest contacting the provider of this sense4.h header file. If they intended it to #included only from C code, there's no real problem with it (other than the IMHO poor style); otherwise, they might consider using #ifdef __cplusplus, declaring the functions with (void) in C and with () in C++. And you could go ahead and make that change yourself. Whether g++ should accept the code or not, with a few changes it would be valid C, valid C++, acceptable to both gcc and g++, and better style.

If you've read this far and you're still awake, I'm impressed.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!