找回密码
 欢迎注册
查看: 22478|回复: 13

[讨论] 奇特的编译 error: C2016

[复制链接]
发表于 2010-3-17 16:14:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?欢迎注册

×
我正在搭建全新的HugeCalc架构,尝试采用mathe曾给出的建议。 但编译时遇到一条提示 error C2016: C requires that a struct or union has at least one member 为了分析问题,我写了个简单的测试程序:
  1. typedef struct _HI{} *PHI;
  2. int main(void)
  3. {
  4. int i;
  5. PHI p;
  6. p = (PHI)&i;
  7. return 0;
  8. }
复制代码
如果存成 test.cpp,在 VC2008 及 VC6 下均顺利编译通过。 但若修改文件名为 test.c,在VC6 下提示:
Deleting intermediate files and output files for project 'test - Win32 Debug'. --------------------Configuration: test - Win32 Debug-------------------- Compiling... test.c e:\jason\test\test.c(1) : error C2059: syntax error : '}' e:\jason\test\test.c(6) : error C2065: 'PHI' : undeclared identifier e:\jason\test\test.c(6) : error C2146: syntax error : missing ';' before identifier 'p' e:\jason\test\test.c(6) : error C2065: 'p' : undeclared identifier Error executing cl.exe. test.exe - 4 error(s), 0 warning(s)
在VC2008下提示:
------ Rebuild All started: Project: test, Configuration: Debug Win32 ------ Deleting intermediate and output files for project 'test', configuration 'Debug|Win32' Compiling... test.c e:\jason\test\test.c(1) : error C2016: C requires that a struct or union has at least one member Build log was saved at "file://e:\Jason\test\Debug\BuildLog.htm" test - 1 error(s), 0 warning(s) ========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========
我想问的是:为什么C中不允许定义空的结构体?而C++既然允许,是什么原因呢?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-17 17:34:53 | 显示全部楼层
C++编译时,应该是会将所有的class,struct都统一为一种C++对象模型。对编译器而言,在语义上,class 和 struct是等价的。 而C++允许定义空类,每个类对象都起码占一个字节(不考虑内存对齐)。 具体的,《Inside The C++ Object Model》讲过。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-17 19:03:35 | 显示全部楼层
是的,C不允许空对象,但是C++由于支持模板类等,经常广泛使用空对象。 不过LZ可以试着直接使用: typedef struct _HI *PHI; 也就是不定义_HI而直接使用其指针。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-3-18 08:26:00 | 显示全部楼层
2# medie2005 看了你的说明, 我突然想到在 C++ 里,class 里会隐藏一个指针,用来记录成员函数地址,或者是虚拟函数表的索引号。 因为不同的class其成员函数地址肯定不一样,正是有因为这个隐藏的变量,可以让编译器进行区分。 而C中不存在上述机制,所以编译器无法进行空结构的区分。 不知上述观点是否正确?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-18 08:29:55 | 显示全部楼层
不正确。 编译器是通过类名来区分是否是同一个类的指针。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-3-18 08:31:32 | 显示全部楼层
3# mathe mathe 就是高,很快就想到了变通手法。
  1. typedef struct _HI *PHI;
  2. typedef struct _HX *PHX;
  3. PHI HI_New( void );
  4. PHX HX_New( void );
  5. void HI_Del( PHI pHI );
  6. void HX_Del( PHX pHX );
复制代码
如果混用了 PHI/PHX 类型,比如:HX_Del( HI_New() ); 则编译时不会报error,但会报 warning C4133: 'function' : incompatible types - from 'PHI' to 'PHX' 应该说基本达到提醒警告的目的了。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-3-18 08:35:37 | 显示全部楼层
不正确。 编译器是通过类名来区分是否是同一个类的指针。 mathe 发表于 2010-3-18 08:29
那为什么C中不可以以结构名进行区分呢?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-18 08:46:54 | 显示全部楼层
C++允许定义空对象,也就是必须允许定义空类。 但一个空类,可以实例化为多个空对象,如何区分这些空对象? 比如class A是空类,定义A test1, test2。 在编译器角度,如何区分test1和test2? 起码,每个空对象都要占用内存空间,以区别于其他空对象。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-3-18 09:15:19 | 显示全部楼层
C中就是用结构名来区分两个不同的结构的。 所以 HX_Del( HI_New() ); 会报告警告,应为这时不同类型之间指针的转化(结构名不同)。 对于C++中的空对象,不会产生真正的内存空间的消耗,或者我们可以赋予任意内存地址空间。具有意义的只有其逻辑值。对于同一个空对象的两个不同实例,通过地址区分它们没有意义。 而C++中的空类主要用于模板类,比如我们可以如下定义一个functor class compare{ public: bool operator()(int a, int b)const; }; 然后我们可以通过比如 compare c; c(1,2) 来调用这个函数。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-3-18 09:38:24 | 显示全部楼层
既然“C中就是用结构名来区分两个不同的结构的”, 那究竟是什么原因必须规定“C requires that a struct or union has at least one member”? 我的意思是:在主题帖的定义下,我们人感觉是合理的,为什么编译器会拒绝呢?根本原因是什么呢?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-11-21 21:33 , Processed in 0.035169 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表