首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用C格式格式化位字段内的联合

用C格式格式化位字段内的联合
EN

Stack Overflow用户
提问于 2016-03-06 17:40:17
回答 2查看 785关注 0票数 3

我有一个特殊的问题,我有一个16位的结构。在结构内部,在成员"x_pos“之后,取决于某些外部标志,接下来的5位表示不同的东西。

如果设置了外部标志,则它们是旋转和缩放参数(rotscale_param),否则上两位是水平和垂直翻转位。

我试图用一个联合来表示这个结构,但是当我看到相当大的(属性)时,我希望看到2个字节,但是结果是4个字节。

我的守则:

代码语言:javascript
复制
typedef unsigned short u16;

struct attribute {
    u16 x_pos : 9;
    union {
        u16 rotscale_param : 5;
        struct {
            u16 unused : 3;
            u16 hflip : 1;
            u16 vflip : 1;
            };
    };
    u16 size : 2;
};

如果有帮助的话,我将尝试为这个结构编写C代码:

代码语言:javascript
复制
OBJ Attribute 
  Bit   Expl.
  0-8   X-Coordinate           
  When Rotation/Scaling used:
    9-13  Rotation/Scaling Parameter Selection
  When Rotation/Scaling not used:
    9-11  Not used
    12    Horizontal Flip      
    13    Vertical Flip        
  14-15 OBJ Size

以上报价来源:http://problemkaputt.de/gbatek.htm#lcdobjoamattributes

以下是一个潜在的解决方案:

代码语言:javascript
复制
typedef struct attr_flag_set {
    u16 x_pos : 9;
    u16 rotscale_param : 5;
    u16 size : 2;
};

typedef struct attr_flag_unset {
    u16 x_pos : 9;
    u16 unused : 3;
    u16 hflip : 1;
    u16 vflip : 1;
    u16 size : 2;
};

union attribute_1 {
    attr_flag_unset attr_unset;
    attr_flag_set attr_set;
};

不过,我不确定这是否是理想的解决方案。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-03-06 18:10:27

要得到正确的包装并不容易。

此外,该标准只允许在声明类型相同的情况下对位进行打包。

来自ISO/IEC 9899 C99,6.7.2.1 Structure and union specifiers

实现可以分配任何大到足以容纳位字段的可寻址存储单元。如果有足够的空间,在结构中立即跟随另一个位场的位场应被封装到同一单元的相邻位中。如果空间不足,是否将不适合的位字段放入下一个单元或重叠相邻单元是实现定义的。在一个单元内分配位字段的顺序(高阶到低阶或低阶到高阶)是实现定义的。可寻址存储单元的对齐未指定。

因此,当您在位字段声明中插入位字段结构时,这违反了规则,并为存储保留了另一个单词。

唯一的解决办法是将声明还原为由两个不同结构组成的联合:

代码语言:javascript
复制
#pragma pack(1)
union attribute
{
    struct
    {
        u16 x_pos : 9;    //See the homogeneous series of declarations
        u16 rotscale_param : 5;
        u16 size : 2;
    } struct1;
    struct
    {
        u16 x_pos  : 9;    //See the homogeneous series of declarations here also
        u16 unused : 3;
        u16 hflip  : 1;
        u16 vflip  : 1;
        u16 size   : 2;
    } struct2;
};

这在C99-C11下适用于我。

不要忘记指示编译器打包数据。正如Mah让我指出的那样,这可以在大多数编译器上使用语用实现,也可以在其他编译器上使用特定的语法来实现。在这种情况下,打包也可以依赖于那些边框应用程序进行编译器。

还请考虑字节顺序依赖于编译器,但在很大程度上取决于CPU的安全性,因此,在小端计算机上工作良好的代码可能会在大端机器上失败。

如果需要完全可移植的代码,最好的做法是使用掩码和移位。

票数 2
EN

Stack Overflow用户

发布于 2016-03-06 18:25:41

如果您试图创建一个使用hflip vflip归档的位,我认为您的意思是执行以下操作:

代码语言:javascript
复制
struct attribute {
    u16 x_pos : 9;
    union {
        u16 rotscale_param : 5;
        struct {
            u16 unused : 3,
                hflip  : 1,
                vflip  : 1;
        } hvflip;
    };
    u16 size : 2;
};

实际上,您正在使用unusedhflipvflip从单个unsigned short创建一个位字段。如另一个答案所示,使用3完全unsigned shorts表示所讨论的5位时,完全忽略了位字段的好处/目的。您只需要一个unsigned-short来表示16位.

下面是一个简单的例子:

代码语言:javascript
复制
#include <stdio.h>

typedef unsigned short u16;

struct attribute {
    u16 x_pos : 9;
    union {
        u16 rotscale_param : 5;
        struct {
            u16 unused : 3,
                hflip  : 1,
                vflip  : 1;
        } hvflip;
    };
    u16 size : 2;
};

void binprnpad (const unsigned long v, size_t sz);

int main (void) {

    struct attribute attr = { .x_pos = 0b101010101,
                              .rotscale_param = 0b10101, 
                              .size = 0b10 };

    printf ("\n attr.x_pos (%3hu)          : ", attr.x_pos);
    binprnpad (attr.x_pos, 9);

    printf ("\n attr.rotscale_param (%3hu) : ", attr.rotscale_param);
    binprnpad (attr.rotscale_param, 5);

    printf ("\n attr.hvflip.unused (%3hu)  : ", attr.hvflip.unused);
    binprnpad (attr.hvflip.unused, 3);
    printf ("\n attr.hvflip.hflip (%3hu)   : ", attr.hvflip.hflip);
    binprnpad (attr.hvflip.hflip, 1);
    printf ("\n attr.hvflip.vflip (%3hu)   : ", attr.hvflip.vflip);
    binprnpad (attr.hvflip.vflip, 1);

    printf ("\n attr.size (%3hu)           : ", attr.size);
    binprnpad (attr.size, 2);
    printf ("\n\n");

    return 0;
}

void binprnpad (const unsigned long v, size_t sz)
{
    if (!sz) { fprintf (stderr, "error: invalid sz.\n"); return; }
    if (!v)  { putchar ('0'); return; }

    while (sz--)
        putchar ((v >> sz & 1) ? '1' : '0');
}

输出

代码语言:javascript
复制
$ ./bin/struct_nested_bin

 attr.x_pos (341)          : 101010101
 attr.rotscale_param ( 21) : 10101
 attr.hvflip.unused (  5)  : 101
 attr.hvflip.hflip (  0)   : 0
 attr.hvflip.vflip (  1)   : 1
 attr.size (  2)           : 10

如果你有什么问题请告诉我。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35830171

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档