我被迫使用第三方加密狗访问库,该库提供包含文件'sense4.h',其代码如下:
#if !defined _WINDOWS_
#define WINAPI
#define CONST const
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned int UINT;
typedef unsigned long ULONG;
typedef char CHAR;
typedef char TCHAR;
typedef void VOID;
...
#endif /* !defined _WINDOWS */
...
unsigned long WINAPI S4Startup(
VOID
);
unsigned long WINAPI S4Cleanup(
VOID
);
...
问题是g ++ 4.6.1抱怨使用typedefed VOID的代码行:
sense4.h:375:9: error: ‘<anonymous>’ has incomplete type
sense4.h:376:1: error: invalid use of ‘VOID {aka void}’
sense4.h:383:9: error: ‘<anonymous>’ has incomplete type
sense4.h:384:1: error: invalid use of ‘VOID {aka void}’
如果不更改'sense.h'包含文件以使我的项目使用g ++编译,我能做些什么吗?
我发现C++ Standard Core Language Closed Issues, Revision 30的第18条规定:
如果parameter-declaration-clause为空,则该函数不带参数。参数列表(void)等同于空参数列表。
可以使用typedef to void而不是参数列表中的void类型吗?
理由:IS已经很清楚,这是不允许的。
答案 0 :(得分:7)
快速摘要:代码无效C ++,虽然它是否应该是一些缺乏明确性。使用void
而不是VOID
,或只使用空括号,可以避免错误。
我认为这是g ++中的一个错误。
我认为这是g ++中的一个错误。我现在确信它不是,尽管我认为最好将此作为警告而不是致命的错误。
通常在C ++中,没有参数的函数用空括号声明:
int foo();
作为对C兼容性的让步,C ++还允许使用void
来表示函数没有参数的C风格原型(因为空括号在C中表示其他内容):
int bar(void);
g ++的解释似乎是这里语法中的void
没有引用不完整的类型 void
;相反,它将它视为一种特殊的语法,并使用了关键字。
我认为您需要修改头文件才能让g ++接受它。
gcc接受它作为有效的C,但如果您需要从C ++源文件中#include
它,这没有用 - 除非您编写C包装并从C ++代码调用它,这可能是可接受的解决方法。
(顺便说一下,我讨厌 typedef那样。typedef void VOID;
的目的是什么?作者是否认为void
过于混乱?我怀疑这是为了与旧的兼容不支持void
关键字的C编译器,但对此的需求早已过去。)
以下是ISO C ++ 2011标准最新草案(8.3.5 [dcl.fct])中的相关描述:
parameter-declaration-clause 确定可以的参数 在调用函数时指定及处理它们。 [... 如果 parameter-declaration-clause 为空,则该函数采用 没有争论。参数列表
(void)
等同于空 参数列表。除了这种特殊情况,void
不应该是 参数类型(虽然派生自void
的类型,例如void*
, 能)。
这意味着void
中的int bar(void);
关键字确实引用了void
类型。 由于typedef名称是命名类型的同义词,对于像int bar(VOID);
应该是同等合法的。VOID
这样的typedef名称来说,最有意义的是接受它void
的{{1}},但标准的措辞实际上是指关键字void
,而不是类型。
允许(void)
的全部目的是C兼容性。只是为了增加混淆,1990 ISO C标准需要void
关键字; 1999和2011 C标准改变了措辞,允许使用typedef。对C++ Defect Report #577的响应确认当前的措辞需要void
关键字,并提出允许typedef的更改 - 但该更改尚未在任何ISO C ++标准中。它可能会出现在C ++ 2011的第一份技术勘误表中,无论何时发布。
感谢another.anon.coward找到现有的gcc bug report。我添加了一个过于冗长的注释,建议代码有效并且不应该生成错误消息 - 以及稍后的注释,承认代码无效,但是警告比致命错误更合适。
与此同时,我建议您与此sense4.h
标头文件的提供商联系。如果他们只想从C代码那里#include
d,那就没有真正的问题(除了恕我直言的穷人风格);否则,他们可能会考虑使用#ifdef __cplusplus
,在C中使用(void)
声明函数,在C ++中使用()
声明函数。你可以继续自己做出改变。无论g ++ 是否接受代码,只需进行一些更改,它就是有效的C,有效的C ++,gcc和g ++都可以接受,以及更好的风格。
如果你已经阅读了这篇文章并且你仍然醒着,我印象深刻。