结构体浅探

结构体浅探

定义以下结构体:

typedef struct {

    uint8_t s1 : 4;

    uint8_t s2 : 4;

    uint8_t s3 : 4;

    uint8_t s4 : 4;

}SS;

该结构体占2字节

由于内存对齐:

typedef struct {

    uint8_t s1 : 4;

}SS;


typedef struct {

    uint8_t s1 : 4;

    uint8_t s2 : 4;

}SS;

都占1字节

则s1-s4各占4 bit,

结构体不初始化:

SS s ;//vs2019编译通过,运行通过。内存信息1100 1100 1100 1100 1100 1100

结构体初始化:

SS s = {0};//vs2019编译通过,运行通过。内存信息0000 0000 0000 0000 1100 1100

SS s = {0,0};//vs2019编译通过,运行通过。内存信息0000 0000 0000 0000 1100 1100

SS s = {0,0,0};//vs2019编译通过,运行通过。内存信息0000 0000 0000 0000 1100 1100

SS s = {0,0,0,0,0};//vs2019编译未通过!!!!!初始值设定项值太多

SS s = {0x11,0x12,0x13};//vs2019编译通过,运行通过。内存信息0010 0001 0000 0011(0x21 0x03)

结论:vs2019中未初始化内存均为0xcc,只要执行初始化,没有预设值均默认0x00,

对于uint8_t s1 : 4;赋值时相当于执行了 &0x0F

赋值:

    s.s1 = 0x01;

    s.s2 = 0x02;

    s.s3 = 0x03;

    s.s4 = 0x04;

uint8_t *ss;

ss = (uint8_t *)&s;

打印输出:

printf(“size:%d\ndata:%x\n%x”,sizeof(s),ss[0],ss[1]);

内存排列情况:

0010 0001 0100 0011

s2 s1 s4 s3

***C语言指针支持类似数组下标索引(ss[0],ss[1]),其长度与(uint8_t *)指针类型相关***

uint8_t改为uint16_t

typedef struct {

    uint16_t s1 : 4;

    uint16_t s2 : 4;

    uint16_t s3 : 4;

    uint16_t s4 : 4;

}SS;

结果不变

性能测试:

结构体:

       s.s1 = 0x11;

        s.s2 = 0x12;

        s.s3 = 0x13;

        s.s4 = 0x14;

对比数组操作(这里控制在四行)

        str_1[0] = 0x11 & 0x0F;

        str_1[0] += (0x12 & 0x0F) << 4;

        str_1[1] = 0x13 & 0x0F;

        str_1[1] += (0x14 & 0x0F) << 4;

循环执行100000000次

更不用说写成两行了

str_1[0] = 0x11 & 0x0F + ((0x12 & 0xFF) << 4);

str_1[1] = 0x13 & 0x0F + ((0x14 & 0xFF) << 4);

查看结构体赋值的汇编代码:

        s.s1 = 0x11;

        s.s2 = 0x12;

        s.s3 = 0x13;

        s.s4 = 0x14;

从汇编代码可以看出,操作流程是先取出变量所在字节,与操作清除对应4bit,或操作存入数据,编译器针对4位的结构体有所优化,在或运算时直接操作位移好的常量。

对于:

str_1[0] = (0x11 & 0x0F) + ((0x12 & 0x0F) << 4);

   str_1[1] = (0x13 & 0x0F) + ((0x14 & 0x0F) << 4);

更加直接,编译器直接计算好进行赋值

将常量改为变量看看:定义一个数组:

uint8_t num[] = { 0x11,0x12,0x13,0x14 };

     s.s1 = num[0];

        s.s2 = num[1];

        s.s3 = num[2];

        s.s4 = num[3];

     str_1[0] = (num[0] & 0x0F) + ((num[1] & 0x0F) << 4);

        str_1[1] = (num[2] & 0x0F) + ((num[3] & 0x0F) << 4);

执行结果(相比常量稍慢一些):

查看汇编代码(34行):

结构体

        s.s1 = num[0];

        s.s2 = num[1];

        s.s3 = num[2];

        s.s4 = num[3];

相比赋值常数,仅仅多出一步取num的值。

数组(26行)

       str_1[0] = (num[0] & 0x0F) + ((num[1] & 0x0F) << 4);

        str_1[1] = (num[2] & 0x0F) + ((num[3] & 0x0F) << 4);

对比以上代码,就性能而言,使用位运算符相比结构体4位的储存方式略显优势,其他使用方式未测试。

moller_1
moller_1
文章: 16

留下评论

您的电子邮箱地址不会被公开。 必填项已用*标注