在嵌入式系统中,一般不建议使用union结构,因为union结构中的各个成员之间存在相互影响,容易滋生问题。可见,union也是把双刃剑。懂得使用它的人可以做到“削铁如泥”,而不懂得使用它的人很可能会被其所伤。下面介绍的几种方法都是嵌入式系统常用的几种技巧。如果熟练掌握,将来定有所用。
1.all的使用
使用all的数据结构模型:
typedef _my_union
{
unsigned int all;
/*sizeof(my_union.my_struct)必须与sizeof(my_union.all)相等*/
struct
{
...
}my_struct;
}my_union;
----------EXAMPLE 1--------
嵌入式系统开发者应该对Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。例如,32bit宽的数 0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址 存放内容
0x4000 0x78
0x4001 0x56
0x4002 0x34
0x4003 0x12
而在Big-endian模式CPU内存中的存放方式则为:
内存地址 存放内容
0x4000 0x12
0x4001 0x34
0x4002 0x56
0x4003 0x78
联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性就可以轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写。
测试代码:
int isLittleEndian()
{
union _dword
{
int all;
struct _bytes
{
char byte0;/*对little来说是最低位,而对big则是最高位*/
char pad[3];
}bytes;
}dword;
dword.all=0x87654321;/*all的功能就是给dword四个字节赋值*/
return (0x21==dword.bytes.byte0);/*查看第一个字节*/
}
分析: 如果你的处理器调用函数isLittleEndian返回1,那么说明你的处理器为little endian,否则为big endian.注意,如果在little endian处理器上,byte0和pad按内存从低到高的存放顺序:LOW->byte0 pad[0] pad[1] pad[2] ->HIGH;0x87654321按内存从低到高的存放顺序: 0x21 0x43 0x65 0x87, 可见byte0对应到0x21。所以通过判断dword中第一个字节dword.bytes.byte0是否与0x21相等就可以看出是否是little endian。
----------EXAMPLE 2--------
#include <stdio.h>
typedef union _student
{
unsigned int all;/*all可以同时清理或设置info中的所有内容*/
struct
{
unsigned int pad: 7;
unsigned int used: 1;/*高位*/
unsigned int personal_id: 8;
unsigned int class_id: 3;
unsigned int subject_id: 6;
unsigned int score: 7;/*低位*/
}info;
}student;
#define MAX_STUDENT_NUM 100
unsigned int students;
unsigned int student_database[MAX_STUDENT_NUM]={0};
int add_to_database(unsigned int data);
int find_from_database(unsigned int personal_id);
int delete_from_database(unsigned int personal_id);
void print_database(void);
void print_student(unsigned int data);
int add_to_database(unsigned int data)
{
student stu;
int i;
for(i=0;i<MAX_STUDENT_NUM;i++)
{
stu.all = student_database[i];
if(!stu.info.used)
{
stu.all = data;
stu.info.used = 1;
student_database[i] = stu.all;
return 1;
}
}
return 0;
}
int find_from_database(unsigned int personal_id)
{
student stu;
int i;
for(i=0;i<MAX_STUDENT_NUM;i++)
{
stu.all = student_database[i];
if(stu.info.used && stu.info.personal_id==personal_id)
{
return stu.all;
}
}
return -1;
}
void print_student(unsigned int data)
{
student stu;
stu.all = data;
printf("personal id %d,class id %d,subject id %d,score %d\n",
stu.info.personal_id,stu.info.class_id,stu.info.subject_id,
stu.info.score);
}
void print_database(void)
{
student stu;
int i;
for(i=0;i<MAX_STUDENT_NUM;i++)
{
stu.all = student_database[i];
if(stu.info.used)
{
print_student(stu.all);
}
}
}
int main(int argc, char *argv[])
{
student jack,jone;
jack.all = 0;
jack.info.personal_id = 102;
jack.info.class_id = 2; /*class 2*/
jack.info.subject_id = 2; /*English*/
jack.info.score = 50; /*fouled*/
add_to_database(jack.all);
jone.all = 0;
jone.info.personal_id = 88;
jone.info.class_id = 2; /*calss 2*/
jone.info.subject_id = 2; /*English*/
jone.info.score = 73; /*passed*/
add_to_database(jone.all);
jack.all = find_from_database(jack.info.personal_id);
if(jack.all<0)
{
printf("no such student with id %d\n",jone.info.personal_id);
}
else
{
printf("found! ");
print_student(jack.all);
}
print_database();
}
运行结果:
found! personal id 102,class id 2,subject id 2,score 50
personal id 102,class id 2,subject id 2,score 50
personal id 88,class id 2,subject id 2,score 73
1.all的使用
使用all的数据结构模型:
typedef _my_union
{
unsigned int all;
/*sizeof(my_union.my_struct)必须与sizeof(my_union.all)相等*/
struct
{
...
}my_struct;
}my_union;
----------EXAMPLE 1--------
嵌入式系统开发者应该对Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。例如,32bit宽的数 0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址 存放内容
0x4000 0x78
0x4001 0x56
0x4002 0x34
0x4003 0x12
而在Big-endian模式CPU内存中的存放方式则为:
内存地址 存放内容
0x4000 0x12
0x4001 0x34
0x4002 0x56
0x4003 0x78
联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性就可以轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写。
测试代码:
int isLittleEndian()
{
union _dword
{
int all;
struct _bytes
{
char byte0;/*对little来说是最低位,而对big则是最高位*/
char pad[3];
}bytes;
}dword;
dword.all=0x87654321;/*all的功能就是给dword四个字节赋值*/
return (0x21==dword.bytes.byte0);/*查看第一个字节*/
}
分析: 如果你的处理器调用函数isLittleEndian返回1,那么说明你的处理器为little endian,否则为big endian.注意,如果在little endian处理器上,byte0和pad按内存从低到高的存放顺序:LOW->byte0 pad[0] pad[1] pad[2] ->HIGH;0x87654321按内存从低到高的存放顺序: 0x21 0x43 0x65 0x87, 可见byte0对应到0x21。所以通过判断dword中第一个字节dword.bytes.byte0是否与0x21相等就可以看出是否是little endian。
----------EXAMPLE 2--------
#include <stdio.h>
typedef union _student
{
unsigned int all;/*all可以同时清理或设置info中的所有内容*/
struct
{
unsigned int pad: 7;
unsigned int used: 1;/*高位*/
unsigned int personal_id: 8;
unsigned int class_id: 3;
unsigned int subject_id: 6;
unsigned int score: 7;/*低位*/
}info;
}student;
#define MAX_STUDENT_NUM 100
unsigned int students;
unsigned int student_database[MAX_STUDENT_NUM]={0};
int add_to_database(unsigned int data);
int find_from_database(unsigned int personal_id);
int delete_from_database(unsigned int personal_id);
void print_database(void);
void print_student(unsigned int data);
int add_to_database(unsigned int data)
{
student stu;
int i;
for(i=0;i<MAX_STUDENT_NUM;i++)
{
stu.all = student_database[i];
if(!stu.info.used)
{
stu.all = data;
stu.info.used = 1;
student_database[i] = stu.all;
return 1;
}
}
return 0;
}
int find_from_database(unsigned int personal_id)
{
student stu;
int i;
for(i=0;i<MAX_STUDENT_NUM;i++)
{
stu.all = student_database[i];
if(stu.info.used && stu.info.personal_id==personal_id)
{
return stu.all;
}
}
return -1;
}
void print_student(unsigned int data)
{
student stu;
stu.all = data;
printf("personal id %d,class id %d,subject id %d,score %d\n",
stu.info.personal_id,stu.info.class_id,stu.info.subject_id,
stu.info.score);
}
void print_database(void)
{
student stu;
int i;
for(i=0;i<MAX_STUDENT_NUM;i++)
{
stu.all = student_database[i];
if(stu.info.used)
{
print_student(stu.all);
}
}
}
int main(int argc, char *argv[])
{
student jack,jone;
jack.all = 0;
jack.info.personal_id = 102;
jack.info.class_id = 2; /*class 2*/
jack.info.subject_id = 2; /*English*/
jack.info.score = 50; /*fouled*/
add_to_database(jack.all);
jone.all = 0;
jone.info.personal_id = 88;
jone.info.class_id = 2; /*calss 2*/
jone.info.subject_id = 2; /*English*/
jone.info.score = 73; /*passed*/
add_to_database(jone.all);
jack.all = find_from_database(jack.info.personal_id);
if(jack.all<0)
{
printf("no such student with id %d\n",jone.info.personal_id);
}
else
{
printf("found! ");
print_student(jack.all);
}
print_database();
}
运行结果:
found! personal id 102,class id 2,subject id 2,score 50
personal id 102,class id 2,subject id 2,score 50
personal id 88,class id 2,subject id 2,score 73