找回密码
 欢迎注册
查看: 16937|回复: 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-3-28 22:33 , Processed in 0.058019 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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