结构和联合
结构:
struct SELF_REF1{
int a;
struct SELF_REF1 b;
int c;
};
这是一种错误的自引用,结构内包含结构体,它也包含自己的b,这样就是一个无止尽的递归程序,相反,换成下面这样,就是正确的。
struct SELF_REF1{
int a;
struct SELF_REF1 *b;
int c;
};
因为编译器在结构的长度确定之前就已经知道指针的长度,所以这种自引用是正确的。
结构的存储分配
struct Align{
char a;
int b;
char c;
};
如果某个机器的整型值长度为4个字节,并且它的存储位置必须被4整除,那么这个结构在内存的存储将如下所示:
这种做法将导致内存浪费。
我们对其成员顺序进行一个调整,如下:
struct Align{
int b;
char a;
char c;
};
这个结构跟前面的一样,但是它只占用8字节,节省33%,两个字符可以紧挨存储,所以只有结构最后面需要跳过两个字节才被浪费。
注:offsetof宏可以用来确定结构中某个成员的实际位置。
offsetof(type,member);
如:
对前面声明的结构体而言,Offsetof(struct Align,b)的返回值是4;
作为函数参数的结构优劣评估
比如有下列结构:
typedef struct{
char product[20];
int quality;
float unit_price;
float total amount;
}Transaction;
现在有个打印函数,并有以下个原型:
void print_receipt(Transaction trans);//结构传递方案
void print_receipt(Transaction* trans); //指针传递方案
这两种的差别在于,第一种传入的是结构体,因为C语言的参数传值调用方式要求把参数的一份拷贝传递给函数,这个结构体共占32个字节,采用这种方式,必须将32个字节复制到堆栈,以后再丢弃。
而第二种传入的是指针,指针比整个结构小得多,所以把它压入堆栈效率高得多,不过,对结构成员的修改将会产生影响。
在结构特别小时,结构传递方案才不会输给指针传递方案。但在绝大多数情况下,指针传递明显效率更高。
联合:
联合的所有成员引用的是内存的统一位置,当你想在不同时刻把不同的东西存储于同一个位置时,就使用联合。
看一个简单例子:
union{
int a;
float b;
}fi;
在一个浮点数和整数都是32位的机器上,变量fi只占用内存中的一个32位的字,如果成员b被使用,这个字就作为浮点数访问,与此相同,a也是一样。
使用联合体可以减少内存使用浪费。
如下:
struct variable{
enum {INT,FLOAT,STRING}type;
int int_value;
float float_value;
char* string_value;
};
分析:该结构主要是根据type的值来输出值的不同类型表示;
但是这里低效的原因就是内存的占用问题——每个variable结构存在两个问使用的值字段。用联合体可以解决这个问题,如下:
struct variable{
enum {INT,FLOAT,STRING}type;
union{
int int_value;
float float_value;
char* string_value;
}
};
type只作为程序员自己负责,内存并不对其进行证实程序使用的是正确的联合成员,而联合体的内存只使用了4个字节,同一位置存储了三种不同类型的值。
联合的长度就是其最长成员的长度。