C语言中的联合体

C语言中的联合体

联合体是C语言中的一个比较好玩的语法,是一个共享内存的一种数据结构,在一些特殊的场合下特别有优势,下面就对联合体做一个简单的介绍。

联合体类型转换

问题:如何实现string类型的到浮点类型的转换?比如一个[0x12, 0x34, 0x56, 0x78]的char型到浮点float型。

实现思路:这个如果用传统的换算方式做会非常复杂,涉及到float类型的存储格式,当然万能的C语言还可以用指针来搞定,一个简单的实现方式是采用联合体union来实现,这个是一个非常典型的共享内存的问题,而union正是为了共享内存设置的。

代码实现

#include "stdio.h"

typedef union _temp_t {
    char s[4];      // char 类型的写入读取方式,1 float = 4 char
    float temp;     // float 类型的写入读取方式
}temp_t;

int main(){
    temp_t value;
    value.s[0] = 0x12;
    value.s[1] = 0x34;
    value.s[2] = 0x56;
    value.s[3] = 0x78;
    printf("Float value is %g\n", value.temp);
    value.temp = 12.3456;
    printf("char value is 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 
        value.s[0], value.s[1], value.s[2], value.s[3]
    );
}

输出

Float value is 1.73782e+34
char value is 0x94, 0x87, 0x45, 0x41

结构体位域

有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

  • 一个位域必须存储在同一个单元中,不能跨两个单元。如一个单元所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:
struct bs 
{ 
    unsigned int a:4 
    unsigned int  :0  
    unsigned int b:4  
    unsigned int c:4 
} 

这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。

  • 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
struct k 
{ 
    int a:1 
    int  :2  
    int b:3 
    int c:2
}; 

位域操作在一些状态位的读取和写入时特别有用,比如下面的一个定义:

typedef union _sdcard_csd {
    unsigned int csd[4];
    struct {
        // csd[0]
        unsigned int                       :2;
        unsigned int file_format           :2;
        unsigned int temp_write_protect    :1;
        unsigned int prem_write_protect    :1;
        unsigned int copy                  :1;
        unsigned int file_format_gpr       :1;
        unsigned int                       :5;
        unsigned int write_bl_partial      :1;
        unsigned int write_bl_len          :4;
        unsigned int r2w_factor            :3;
        unsigned int                       :2;
        unsigned int wp_grp_enable         :1;
        unsigned int wp_grp_size           :7;
        unsigned int sector_size_1         :1;

        // csd[1]
        unsigned int sector_size_2         :6;  // 不能跨单元,所以只有分成两个。
        unsigned int erase_blk_en          :1;
        unsigned int                       :1;
        unsigned int c_size                :22;
        unsigned int                       :2;

        // csd[2]
        unsigned int                       :4;
        unsigned int dsr_imp               :1;
        unsigned int read_blk_misalign     :1;
        unsigned int write_blk_misalign    :1;
        unsigned int read_bl_partial       :1;
        unsigned int read_bl_len           :4;
        unsigned int ccc                   :12;
        unsigned int tran_speed            :8;

        // csd[3]
        unsigned int nsac                  :8;
        unsigned int taac                  :8;
        unsigned int                       :6;
        unsigned int csd_struct            :2;
        unsigned int                       :8;
    };
} sdcard_csd;

上述代码就实现了一个128bit到各种状态的一个映射。


本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。

发表新评论