如何将结构打包到数组中并删除零填充? [英] How to pack structs in array and remove zero-padding?

查看:21
本文介绍了如何将结构打包到数组中并删除零填充?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我理解,"there will never be padding in between elements of an array"。而且我知道结构必须至少有一个字节长,否则它将用零填充。

我希望有一个结构数组,每个结构的大小为4位,没有补零。是否有某种我可以应用于数组的打包方法?

我希望我的输出为0xFFFF(0b1111_1111_1111_1111),但我无法摆脱结构的填充。

#include <stdio.h>
#include <stdint.h>
#include <string.h>

int main() {

    struct data_struct {
        unsigned a: 1;
        unsigned b: 3;
    } __attribute__((packed));  // avoid structure padding

    union {
        struct data_struct data[4];
        uint16_t data_uint;
    } union_data;

    memset(&union_data.data_uint, 0, sizeof(union_data.data_uint));
    for (int i = 0; i < 4; ++i) {
        union_data.data[i].a = 1;
        union_data.data[i].b = 7;
    }

    printf("union_data = 0x%04X
", union_data.data_uint);  // 0x0F0F  == 0b0000_1111_0000_1111
    return 0;
}

推荐答案

是否有某种我可以应用于数组的打包方法?

不,没有。字节是最低的可寻址单位,它至少为8位,因此所有变量将至少与8位对齐,并且大小至少为8位。

如何将结构打包到数组中并删除补零?

不要。编写访问器函数并使用位操作来分配和检索数据。更喜欢编写可移植代码。

也不喜欢使用位字段-请注意,字节内位字段的顺序(LSB与MSB)是由实现定义的,位字段之间的填充也是由实现定义的。为了便于移植,请使用位操作编写访问器函数。

的想法是struct data_struct data[4]中的第二个和第四个元素将从字节边界的中间开始-这是不可能的。对于您的情况,如果您希望以这种方式访问数据,则必须从正确对齐的结构内的打包并集中提取数据:

  union union_data_t {
        struct {
            unsigned char a1 : 1;
            unsigned char b1 : 3;
            unsigned char a2 : 1;
            unsigned char b2 : 3;
        } data[2];
        uint16_t data_uint;
   } union_data;
   struct mydata union_data_get(union union_data_t *t, unsigned idx) {
       struct mydata r;
       r.a = idx%2 ? t->data[idx/2].a2 : t->data[idx/2].a1;
       r.b = idx%2 ? t->data[idx/2].b2 : t->data[idx/2].b1;
       return r;
   }
   void union_data_get(union union_data_t *t, unsigned idx, struct mydata mydata) {
       if (idx%2) { t->data[idx/2].a2 = mydata.a; }
       else { t->data[idx/2].a1 = mydata.a; }
       if (idx%2) { t->data[idx/2].b2 = mydata.b; }
       else { t->data[idx/2].b1 = mydata.b; }
   }

听起来像是GCC特有的最佳抽象,但现在已经没有理由使用位域了--无论如何,访问器函数都可以使用位操作编写:

#include <stdio.h>
#include <stdint.h>
#include <string.h>

struct data_struct {
    unsigned a: 1;
    unsigned b: 3;
} __attribute__((packed));  // avoid structure padding

struct data_struct data_struct_array_get(unsigned char *t, unsigned idx) {
    const unsigned mask = 4 * (idx % 2);
    unsigned v = (t[idx/2] >> mask) & 0xf;
    return (struct data_struct){v>>3, v};
}
void data_struct_array_set(unsigned char *t, unsigned idx, struct data_struct data) {
    const unsigned v = data.a << 3 | data.b;
    const unsigned mask = 4 * (idx % 2);
    t[idx/2] &= ~(0xf << mask);
    t[idx/2] |= v << mask;
} 

int main() {
    union union_data_t {
        unsigned char data[2];
        uint16_t data_uint;
    } union_data;
    
    for (int i = 0; i < 4; ++i) {
        data_struct_array_set(union_data.data, i, 
            (struct data_struct){1, 7}
        );
    }

    printf("union_data = 0x%04X
", union_data.data_uint);
    return 0;
}

这篇关于如何将结构打包到数组中并删除零填充?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆