enum,struct,union类型使用和长度

VC,C++ Builder和lcc三个编译器 间枚举类型enum长度的情况.  

各种C编译器默认的字节对齐数不一致,要写通用的代码,经常就是使用

#pragma pack(1) ... 

#pragma pack() 

来使编译器以单字节对齐. 

今天在bcb5中调用vc6的dll时出现错误,但在VC中调用dll却很正常,说明很有可能是编译器之间的差异造成.仔细debug后发现bcb和vc的枚举类型长度不一样,即便使用了#pragma pack(1)编译开关. 如以下程序: /*---------------------*/ #pragma pack(1) typedef enum {     ENUMITEM1=0,     ENUMITEM2,     ENUMITEM3 } ENUM; #pragma pack() ENUM mENUM; sizeof(mENUM); /*---------------------*/ 

在VC6和LCC3.3中为四字节,而在BCB中即为1字节.再试以下程序

/*---------------------*/

#pragma pack(4)

typedef enum {

    ENUMITEM1=0,

    ENUMITEM2,

    ENUMITEM3

} ENUM;

#pragma pack()

ENUM mENUM;

sizeof(mENUM);



/*---------------------*/ 

在VC和LCC中依然是4字节,而在BCB中也还是1字节,由于手上暂时没有GCC,所以不能看GCC的情况. 

以上说明枚举类型作为C的标准变量类型,其长度是不受编译开关影响的,就如char类型无论如何pack,依然是单字节.



但是,并非所有的编译器都遵循C标准,或许是VC不标准,或许是BCB不标准. 

所以建议以后用到的变量尽量使用char或int来替代enum,以免带来不必要的麻烦. 

#include <stdio.h>

int main()

{

      enum Color

      {

          GREEN = 1,

          RED,

          BLUE,

         GREEN_RED = 10,

         GREEN_BLUE,

      }c;

     printf("%d,%d,%d,",GREEN,RED,BLUE);

     printf("%d,%d\n",GREEN_RED,GREEN_BLUE);

     printf("%d\n",sizeof(c));

     return 0;

}

      看到这里,是不是一开始想用c.GREEN,c.RED,c.BLUE...来表示枚举变量里面的成员?然后这样子表示,编译器是会报错的。为什么不能像结构体那样表示呢?因为结构体里面的成员是变量,而枚举里面的成员是常量啊!(这是我个人的理解)

      枚举变量究竟是多大呢?答案是4,为啥呢?因为,枚举变量的取值为花括号内的任意一个值(有且只能有其中一个值),而这个值是int型的,在X86系统中,int型的数据占内存4个字节。所以sizeof(c) = 4,也就是枚举变量的值为4。
一般编译器都有选项的

BCB:

* -b      Make enums integer-sized (-b- makes them short as possible)

GCC:

-fshort-enums Use the narrowest integer type possible for enumeration types

VC Same as int
枚举默认是用int类型来存储的,32位系统下占4个字节。可以存储的最大值是0xffffff。 你可以改变枚举的大小例如enum TypeChar : unsigned char{} 这样可以节省空间, 在嵌入式编程中较为常见。嵌入式编程中,甚至有用位来存储的。
枚举并不放在类的对象里,类A里面没有任何东西,与class A {};相同大小。不包含任何东西的类的大小就是1。cout << sizeof(A) << endl;输出的是1
关于C++和C的区别:

1.区别最大的是struct,C++中的struct几乎和class一样了,可以有成员函数,而C中的struct只能包含成员变量。 enum,union没区别。
2.C++要考虑字节对齐。 struct的定义:
struct 结构标签 { 类型1 标识符1; 类型2 标识符2; 类型3 标识符3; 类型4 标识符4; 类型5 标识符5; }; 1、建议将struct的声明和变量的定义分开写, 2、struct内可以放任何类型的变量声明。 struct的内存对齐: 对齐原则: 1、数据成员对齐规则。每个数据成员存储的起始位置要从该成员大小的整数倍开始。 2、数据成员包含结构体:结构体成员要从其内部最大元素大小的整数倍地址开始存储。 3、结构体的总大小:是其内部最大基本成员的整数倍,不足的要补齐。 这个似乎不太重要,没有太大的关系。也就是某些面试或考试题中的难为人的地方了。 union的定义: union 联合标签 { 类型1 标识符1; 类型2 标识符2; 类型3 标识符3; 类型4 标识符4; 类型5 标识符5; }; 联合体与结构体的区别: 1、结构体中,每个变量依次存储。 2、联合体中,每个变量都是从偏移地址零开始存储,每次只有一个成员存储于该地址。 enum的定义: enum 枚举标签{small, media =7, large =10,humungous}; 1、枚举通过简单的操作将一串名字和一串整型值相联系起来。 2、缺省情况下,枚举从零开始,如果对列表中的某一个标识符赋值,下一个标识符值比前面一个的值大1. 3#define 定义的值在编译时候消失,但是枚举定义的,则在调试的过程任然是可见的,可以在代码调试中使用它们。 其实 enum可以相对应define来使用。 举个例子: union a { int b; char c; }; a abc; abc.b=4; abc.c=5; //或者也可以直接在定义时定义变量 union a { int b; char c; }abc; abc.b=4; abc.c=5; 或者: typedef union { int b; char c; }a; a abc; abc.b=4; abc.c=5; 仔细的看看,很重要,老是用的不对,自己给自己找麻烦的。 ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// struct的最终大小考虑是最大的那个类型的倍数和每个都要对齐; enum的大小考虑是最大的那个 enum是枚举,就是某个变量的值是能够列举的,比如,星期的话就每周1到7,月的话就1到12、而struct的话是对于某个变量是有很多数据类型构成一个总体的,比如学生这个变量,他需要学号,姓名,年龄,性别等等,这个时候就需要定义结构体了。而uninon的话呢,其中定义的变量都只占一同块内存。。。 对于结构体:考虑要对齐和占用最大空间的元素所占空间的倍数 对于联合体:考虑是里面所有类型数据占用空间的倍数同时还要比最大的那个还要大的最小数,就是联合体占用的空间,注意数组类型的处理!!! typedef enum { ANUnknown = 0, ANShapeFile = 1, ANSDEDatabase = 2, ANFileDatabase = 3, ANRasterFile = 4 }ANDataType; sizeof(ANDataType) 为 4 ====================================================== struct AAA { double d; char ss; char s; }; sizeof(AAA) 为结构中长度最大的变量的倍数(遵循内存对齐的原则),如上,double 的长度为 8, 则整个为 8*2 = 16 因为 char 长度为1,两个char 为2,仍小于8,故按8计算,若有9个char变量,则其中 8个char 合计为 8,剩余一个不足8 按 8字节计算。比如: struct AAA { double d; char s1; char s2; char s3; char s4; char s5; char s6; char s7; char s8; char s9; }; 按结构体中的变量的长度叠加,则大小为 8+(1+1+1+1+1+1+1+1)+1 = 1716 < 17 < 24, 则结构体的大小为 24 比如, struct AAA { double d; char s1; int i; }; 按结构体中的变量的长度叠加,则大小为 8+1+4 = 138 < 13 < 16, 则结构体的大小为 16 ====================================================== union AAA { double d; int i; }; 联合,则以定义中最大的数据类型的长度为准,此联合的 size 为 8 备注: union 与 struct 的大小与其内部定义的函数无关!!!
typedef struct与struct的区别



1. 基本解释



  typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。



  在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。



  至于typedef有什么微妙之处,请你接着看下面对几个问题的具体阐述。



  2. typedef & 结构的问题



  当用下面的代码定义一个结构时,编译器报了一个错误,为什么呢?莫非C语言不允许在结构中包含指向它自己的指针吗?请你先猜想一下,然后看下文说明:



typedef struct tagNode

{

 char *pItem;

 pNode pNext;

} *pNode; 



  答案与分析:



  1、typedef的最简单使用



typedef long byte_4;



  给已知数据类型long起个新名字,叫byte_4。



  2、 typedef与结构结合使用



typedef struct tagMyStruct

{ 

 int iNum;

 long lLength;

} MyStruct;



  这语句实际上完成两个操作:



  1) 定义一个新的结构类型



struct tagMyStruct

{ 

 int iNum; 

 long lLength; 

};



  分析:tagMyStruct称为“tag”,即“标签”,实际上是一个临时名字,struct 关键字和tagMyStruct一起,构成了这个结构类型,不论是否有typedef,这个结构都存在。



  我们可以用struct tagMyStruct varName来定义变量,但要注意,使用tagMyStruct varName来定义变量是不对的,因为struct 和tagMyStruct合在一起才能表示一个结构类型。



  2) typedef为这个新的结构起了一个名字,叫MyStruct。



typedef struct tagMyStruct MyStruct;



  因此,MyStruct实际上相当于struct tagMyStruct,我们可以使用MyStruct varName来定义变量。



  答案与分析



  C语言当然允许在结构中包含指向它自己的指针,我们可以在建立链表等数据结构的实现上看到无数这样的例子,上述代码的根本问题在于typedef的应用。



  根据我们上面的阐述可以知道:新结构建立的过程中遇到了pNext域的声明,类型是pNode,要知道pNode表示的是类型的新名字,那么在类型本身还没有建立完成的时候,这个类型的新名字也还不存在,也就是说这个时候编译器根本不认识pNode。



  解决这个问题的方法有多种:



  1)、



typedef struct tagNode {  char *pItem;  struct tagNode *pNext; } *pNode;



  2)、



typedef struct tagNode *pNode;

struct tagNode 

{

 char *pItem;

 pNode pNext;

};



  注意:在这个例子中,你用typedef给一个还未完全声明的类型起新名字。C语言编译器支持这种做法。



  3)、规范做法:



struct tagNode

{

 char *pItem;

 struct tagNode *pNext;

};

typedef struct tagNode *pNode;

 

你可能感兴趣的:(struct)