【问题标题】:How to add an array to a bitfield struct?如何将数组添加到位域结构?
【发布时间】:2015-09-08 15:47:16
【问题描述】:

我尝试将结构中的位字段用于某些只需要一位或两位而不是整个字节的值。

我的代码是:

struct s_rdata {
    signed int      p0:28; 
    signed int      p1:28; 
    signed int      p2:28; 
    unsigned int    d0:17; 
    unsigned int    d1:17; 
    unsigned int    d2:17; 
    unsigned char   data1:1; 
    unsigned char   data2:1; 
} rdata; 

因此,您可能会看到名为 p0 - p2d0 - d2data1 - data2 的变量。

我现在想将它们放在一个数组中。但是,这些行都不起作用:

signed int p[3]:28; 
signed int p:28[3]; 

我不能将数组添加到位域列表中,signed int 的数组每个条目只需要 28 位吗?

【问题讨论】:

    标签: c struct bit-fields


    【解决方案1】:

    不,你不能有一个位域数组,也不能有一个基本类型是数组类型的位域。后者甚至没有意义。前者会适得其反,因为您首先会失去使用位域获得的任何空间效率。

    您可以拥有一个包含单个位域成员的 structs 数组:

    struct container {
      signed int bitfield:7;
    } array[3];
    

    但同样,您将失去与位域使用相关的任何空间效率。

    当然,您可以创建任何struct 类型的数组,包括具有多个位域成员的数组。在这种情况下,您可能会在各个结构中实现一些内部空间效率,但您可能会在每个结构的末尾看到填充,这会降低数组的整体空间效率。

    最终,除非您的程序的内存消耗与其目标环境相比过多,否则我强烈建议您忘记位域。它们会使您的生活变得复杂,以获得不确定的重要性和不确定的收益,而这种收益可能会被性能下降(幅度和重要性不确定)所抵消。

    如果您最终确定该程序确实使用了过多的内存,那么一定要测试您所做的任何更改,看看它产生了多少改进,以及成本是多少。

    【讨论】:

    • 如果使用结构数组,pragma pack 语句是否有助于解决空间效率低下的问题?
    • @ryyker,也许吧。 #pragma pack 效果的细节是特定于实现的。如果它有任何影响,特定用途可能会或可能不会阻止编译器布置带有内部或尾随填充的结构,代价是可能导致成员未对齐。除非您尝试将 struct 类型映射到特定的外部定义的数据模式,否则通常最好手动将成员从最大对齐要求布置到最小;这通常可以避免引入任何内部填充,但仍可能存在尾随填充。
    【解决方案2】:

    我同意@John 关于空间效率低下的评估,但尽管如此,这是一个在结构数组中包含位字段内容的想法:

    typedef struct
    {
      int A : 16;
      int B : 16;
    } Struct1;
    
    typedef struct
    {
      Struct1 B;//bitfield struct
      int array[10];//combined with array (of any legal type)
    }
    

    这里是一个用位结构的内容填充数组的例子:

    typedef struct {
        signed int      p0:28; 
        signed int      p1:28; 
        signed int      p2:28; 
        unsigned int    d0:17; 
        unsigned int    d1:17; 
        unsigned int    d2:17; 
        unsigned char   data1:1; 
        unsigned char   data2:1; 
    } RDATA; 
    
    
    typedef struct {
        int A[3];
        unsigned int B[3];
        unsigned char C[2];
    } ARRAY;
    
    RDATA rdata = {//initialize instance of RDATA with data
        28,
        28,
        28,
        17,
        17,
        17,
        1,
        1
    };
    
    int WriteToArray(ARRAY *a);
    
    int main(void)
    {
        ARRAY a;
        WriteToArray(&a);//populate array with RDATA values
    
        //ARRAY is now populated with bitfield values;
        a.A[0];
        a.A[1];
        //and so on
    
        return 0;
    }
    
    WriteToArray(ARRAY *a)
    {
        a->A[0]=rdata.p0;//using values initialized above
        a->A[1]=rdata.p1;
        a->A[2]=rdata.p2;
        a->B[0]=rdata.d0;
        a->B[1]=rdata.d1;
        a->B[2]=rdata.d2;
        a->C[0]=rdata.data1;
        a->C[1]=rdata.data2;
        return 0;
    }
    

    您还可以尝试使用 pragma pack 语句来查看对空间的影响,但请参阅您帖子下方的@John 评论,了解有关编译指示和间距的其他注意事项。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-02
      • 2013-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-31
      相关资源
      最近更新 更多