您的位置:控制工程论坛网论坛 » 嵌入式系统 » union在嵌入式编程中的3个妙用(上)

junhong07

junhong07   |   当前状态:在线

总积分:7915  2024年可用积分:1

注册时间: 2008-01-15

最后登录时间: 2019-06-23

空间 发短消息加为好友

union在嵌入式编程中的3个妙用(上)

junhong07  发表于 2009/10/21 20:53:35      933 查看 0 回复  [上一主题]  [下一主题]

手机阅读

在嵌入式系统中,一般不建议使用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;/* 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};
 
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

2. union巧妙地实现多字化节数据类型之间的转化
 
在涉及音视频编解码算法中,经常会涉及一些数据压缩、声音解码、图象的缩放等问题。
这里通过一个例子来推荐一种union绝妙用法(这种方法由Equator公司提供,在我们公司的图象处理算法中用得很多)。在该例子中,利用union结构n64u实现占8个字节n64类型与单字节的c0~c7的相互转换,从而达到数据压缩和分解的目的。
 
#include <stdio.h>
#define IN
#define OUT
#define INOUT
typedef unsigned long long  n64;
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;
 
/*利用n64和c0~c7占用同一内存区,实现它们之间的相互转换*/
typedef union {
        n64     n64;
        struct {
                n32 l0, l1;
        } u32;
        struct {
                long l0, l1;
        } s32;
        struct {
                unsigned short s0, s1, s2, s3;
        } u16;
        struct {
                short s0, s1, s2, s3;
        } s16;
        struct {
                unsigned char c0, c1, c2, c3, c4, c5, c6, c7;
        } u8;
        struct {
             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 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;
 
 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;
}
 
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;   
 }   
}

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",
         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");  
}
 
/*
运行结果:
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
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
*/
1楼 0 0 回复