在嵌入式系统中,一般不建议使用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;
}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);/*查看第一个字节*/
}
{
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;/* 7 bit */
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;
{
unsigned int all;/*all可以同时清理或设置info中的所有内容*/
struct
{
unsigned int pad: 7;/* 7 bit */
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};
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,
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*/
}
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();
}
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
personal id 102,class id 2,subject id 2,score 50
personal id 88,class id 2,subject id 2,score 73
2. union巧妙地实现多字化节数据类型之间的转化
在涉及音视频编解码算法中,经常会涉及一些数据压缩、声音解码、图象的缩放等问题。
这里通过一个例子来推荐一种union绝妙用法(这种方法由Equator公司提供,在我们公司的图象处理算法中用得很多)。在该例子中,利用union结构n64u实现占8个字节n64类型与单字节的c0~c7的相互转换,从而达到数据压缩和分解的目的。
int main(int argc, char *argv[])
{
n64 n64data[MAX_DATA_COMPRESSED_NUM];
n8 n8data[MAX_DATA_COMPRESSED_NUM];
s8t s8t_data[MAX_DATA_COMPRESSED_NUM]
=
{/*即将被压缩的数据,一个数据占一个字节*/
{1,2,3,4,5,6,7,8},/*8个字节被压缩成单个字节*/
{2,2,3,4,5,6,7,7},
{3,2,3,4,5,6,7,6},
{4,2,3,4,5,6,7,5},
{5,2,3,4,5,6,7,4},
{6,2,3,4,5,6,7,3},
{7,2,3,4,5,6,7,2},
{8,7,6,5,4,3,2,1}
};
n16 i,n=MAX_DATA_COMPRESSED_NUM;
printf("data:\n");
for(i=0;i<n;i++)
{
n64data[i] = *(n64*)&s8t_data[i];
printf("%3u %3u %3u %3u %3u %3u %3u %3u\n",
这里通过一个例子来推荐一种union绝妙用法(这种方法由Equator公司提供,在我们公司的图象处理算法中用得很多)。在该例子中,利用union结构n64u实现占8个字节n64类型与单字节的c0~c7的相互转换,从而达到数据压缩和分解的目的。
#include <stdio.h>
#define IN
#define OUT
#define INOUT
#define OUT
#define INOUT
typedef unsigned long long n64;
typedef unsigned int n32;
typedef unsigned short n16;
typedef unsigned char n8;
typedef unsigned int n32;
typedef unsigned short n16;
typedef unsigned char n8;
typedef struct _s8t{
unsigned char c0, c1, c2, c3, c4, c5, c6, c7;
}s8t;
unsigned char c0, c1, c2, c3, c4, c5, c6, c7;
}s8t;
/*利用n64和c0~c7占用同一内存区,实现它们之间的相互转换*/
typedef union {
n64 n64;
n64 n64;
struct {
n32 l0, l1;
} u32;
n32 l0, l1;
} u32;
struct {
long l0, l1;
} s32;
long l0, l1;
} s32;
struct {
unsigned short s0, s1, s2, s3;
} u16;
unsigned short s0, s1, s2, s3;
} u16;
struct {
short s0, s1, s2, s3;
} s16;
short s0, s1, s2, s3;
} s16;
struct {
unsigned char c0, c1, c2, c3, c4, c5, c6, c7;
} u8;
unsigned char c0, c1, c2, c3, c4, c5, c6, c7;
} u8;
struct {
char c0, c1, c2, c3, c4, c5, c6, c7;
} s8;
} n64u;
char c0, c1, c2, c3, c4, c5, c6, c7;
} s8;
} n64u;
#define MAX_DATA_COMPRESSED_NUM 8
int compress64_8(IN const n64* src,IN n16 n,OUT n8* dst);
int uncompress8_64(IN const n8* src,IN n16 n,OUT n64* dst);
int uncompress8_64(IN const n8* src,IN n16 n,OUT n64* dst);
int compress64_8(IN const n64* src,IN n16 n,OUT n8* dst)
{
n64u n64u_data;
register n64* n64ptr=(n64*)src;
register n8* n8ptr=dst;
n16 i="0",num=n;
{
n64u n64u_data;
register n64* n64ptr=(n64*)src;
register n8* n8ptr=dst;
n16 i="0",num=n;
if(NULL==n64ptr || NULL==n8ptr || n<1)
{
printf("invalid param,src 0x%x,dst 0x%x,n %d\n",n64ptr,n8ptr,n);
return 0;
}
for(i=0;i<num;i++)
{
n64u_data.n64 = *n64ptr++;
/*用简单的均值法将8个点压缩成1个点*/
*n8ptr++ = (n64u_data.u8.c0+n64u_data.u8.c1+n64u_data.u8.c2+\
n64u_data.u8.c3+n64u_data.u8.c4+n64u_data.u8.c5+\
n64u_data.u8.c6+n64u_data.u8.c7)/(sizeof(n64)/sizeof(n8));
}
return 1;
}
{
printf("invalid param,src 0x%x,dst 0x%x,n %d\n",n64ptr,n8ptr,n);
return 0;
}
for(i=0;i<num;i++)
{
n64u_data.n64 = *n64ptr++;
/*用简单的均值法将8个点压缩成1个点*/
*n8ptr++ = (n64u_data.u8.c0+n64u_data.u8.c1+n64u_data.u8.c2+\
n64u_data.u8.c3+n64u_data.u8.c4+n64u_data.u8.c5+\
n64u_data.u8.c6+n64u_data.u8.c7)/(sizeof(n64)/sizeof(n8));
}
return 1;
}
int uncompress8_64(IN const n8* src,IN n16 n,OUT n64* dst)
{
n64u n64u_data;
register n64* n64ptr=dst;
register n8* n8ptr=(n8*)src;
register n8 n8data;
n16 i="0",num=n;
if(NULL==n64ptr || NULL==n8ptr || n<1)
{
printf("invalid param,src 0x%x,dst 0x%x,n %d\n",n64ptr,n8ptr,n);
return 0;
}
for(i=0;i<num;i++)
{
n8data=*n8ptr++;
/*将1个点解压成8个点,采用简单的还原,所以有失真*/
n64u_data.u8.c0 = n8data;
n64u_data.u8.c1 = n8data;
n64u_data.u8.c2 = n8data;
n64u_data.u8.c3 = n8data;
n64u_data.u8.c4 = n8data;
n64u_data.u8.c5 = n8data;
n64u_data.u8.c6 = n8data;
n64u_data.u8.c7 = n8data;
*n64ptr++ = n64u_data.n64;
}
}
{
n64u n64u_data;
register n64* n64ptr=dst;
register n8* n8ptr=(n8*)src;
register n8 n8data;
n16 i="0",num=n;
if(NULL==n64ptr || NULL==n8ptr || n<1)
{
printf("invalid param,src 0x%x,dst 0x%x,n %d\n",n64ptr,n8ptr,n);
return 0;
}
for(i=0;i<num;i++)
{
n8data=*n8ptr++;
/*将1个点解压成8个点,采用简单的还原,所以有失真*/
n64u_data.u8.c0 = n8data;
n64u_data.u8.c1 = n8data;
n64u_data.u8.c2 = n8data;
n64u_data.u8.c3 = n8data;
n64u_data.u8.c4 = n8data;
n64u_data.u8.c5 = n8data;
n64u_data.u8.c6 = n8data;
n64u_data.u8.c7 = n8data;
*n64ptr++ = n64u_data.n64;
}
}
int main(int argc, char *argv[])
{
n64 n64data[MAX_DATA_COMPRESSED_NUM];
n8 n8data[MAX_DATA_COMPRESSED_NUM];
s8t s8t_data[MAX_DATA_COMPRESSED_NUM]
=
{/*即将被压缩的数据,一个数据占一个字节*/
{1,2,3,4,5,6,7,8},/*8个字节被压缩成单个字节*/
{2,2,3,4,5,6,7,7},
{3,2,3,4,5,6,7,6},
{4,2,3,4,5,6,7,5},
{5,2,3,4,5,6,7,4},
{6,2,3,4,5,6,7,3},
{7,2,3,4,5,6,7,2},
{8,7,6,5,4,3,2,1}
};
n16 i,n=MAX_DATA_COMPRESSED_NUM;
printf("data:\n");
for(i=0;i<n;i++)
{
n64data[i] = *(n64*)&s8t_data[i];
printf("%3u %3u %3u %3u %3u %3u %3u %3u\n",
s8t_data[i].c0,s8t_data[i].c1,s8t_data[i].c2,
s8t_data[i].c3,s8t_data[i].c4,s8t_data[i].c5,
s8t_data[i].c6,s8t_data[i].c7);
}
printf("\n");
compress64_8(n64data,n,n8data);
printf("compressed to:\n");
for(i=0;i<n;i++)
{
printf("%3u ",n8data[i]);
}
printf("\n\n");
uncompress8_64(n8data,n,n64data);
printf("uncompressed to:\n");
for(i=0;i<n;i++)
{
*(n64*)&s8t_data[i] = n64data[i];
printf("%3u %3u %3u %3u %3u %3u %3u %3u\n",
}
printf("\n");
compress64_8(n64data,n,n8data);
printf("compressed to:\n");
for(i=0;i<n;i++)
{
printf("%3u ",n8data[i]);
}
printf("\n\n");
uncompress8_64(n8data,n,n64data);
printf("uncompressed to:\n");
for(i=0;i<n;i++)
{
*(n64*)&s8t_data[i] = n64data[i];
printf("%3u %3u %3u %3u %3u %3u %3u %3u\n",
s8t_data[i].c0,s8t_data[i].c1,s8t_data[i].c2,
s8t_data[i].c3,s8t_data[i].c4,s8t_data[i].c5,
s8t_data[i].c6,s8t_data[i].c7);
}
printf("\n");
}
}
printf("\n");
}
/*
运行结果:
data:
1 2 3 4 5 6 7 8
2 2 3 4 5 6 7 7
3 2 3 4 5 6 7 6
4 2 3 4 5 6 7 5
5 2 3 4 5 6 7 4
6 2 3 4 5 6 7 3
7 2 3 4 5 6 7 2
8 7 6 5 4 3 2 1
运行结果:
data:
1 2 3 4 5 6 7 8
2 2 3 4 5 6 7 7
3 2 3 4 5 6 7 6
4 2 3 4 5 6 7 5
5 2 3 4 5 6 7 4
6 2 3 4 5 6 7 3
7 2 3 4 5 6 7 2
8 7 6 5 4 3 2 1
compressed to:
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
uncompressed to:
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
*/
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
*/