【问题标题】:Converting Bit Field to int将位字段转换为 int
【发布时间】:2011-01-28 22:46:59
【问题描述】:

我有这样声明的位字段:

typedef struct morder {
    unsigned int targetRegister : 3;
    unsigned int targetMethodOfAddressing : 3;
    unsigned int originRegister : 3;
    unsigned int originMethodOfAddressing : 3;
    unsigned int oCode : 4;
} bitset;

我也有 int 数组,我想从这个数组中获取 int 值,它代表这个位字段的实际值(实际上是某种机器字,我有它的一部分,我想要整个单词的 int 表示)。

【问题讨论】:

  • @shaharg:我认为你的语言不太准确。位字段是结构中的各个字段,但您似乎将整个结构称为“位字段”。

标签: c bit-fields


【解决方案1】:

只需使用联合。然后,您可以以 16 位 int 或单个位字段的形式访问您的数据,例如

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

typedef struct {
    unsigned int targetRegister : 3;
    unsigned int targetMethodOfAddressing : 3;
    unsigned int originRegister : 3;
    unsigned int originMethodOfAddressing : 3;
    unsigned int oCode : 4;
} bitset;

typedef union {
    bitset b;
    uint16_t i;
} u_bitset;

int main(void)
{
    u_bitset u = {{0}};
    
    u.b.originRegister = 1;
    printf("u.i = %#x\n", u.i); 

    return 0;
}

【讨论】:

    【解决方案2】:

    你可以使用联合:

    typedef union bitsetConvertor {
        bitset bs;
        uint16_t i;
    } bitsetConvertor;
    
    bitsetConvertor convertor;
    convertor.i = myInt;
    bitset bs = convertor.bs;
    

    或者你可以使用演员表:

    bitset bs = *(bitset *)&myInt;
    

    或者您可以在联合中使用匿名结构:

    typedef union morder {
        struct {
            unsigned int targetRegister : 3;
            unsigned int targetMethodOfAddressing : 3;
            unsigned int originRegister : 3;
            unsigned int originMethodOfAddressing : 3;
            unsigned int oCode : 4;
        };
    
        uint16_t intRepresentation;
    } bitset;
    
    bitset bs;
    bs.intRepresentation = myInt;
    

    【讨论】:

    • 否决:bitset bs = *(bitset *)&amp;myInt; 是打破严格别名规则的经典示例。
    • uint16_t 不能保证unsigned int。联合取决于实现细节;位域结构对其布局几乎没有任何保证。强制转换违反了有效类型(又名严格别名)规则 -> 未定义的行为。方法不好。
    【解决方案3】:

    请,请,不要使用联合。或者,更确切地说,通过使用联合来了解您在做什么——最好在使用联合之前。

    正如您在this answer 中看到的,不要依赖位域来进行移植。特别是对于您的情况,结构中位域的顺序取决于实现。

    现在,如果您的问题是,如何将位域结构打印为 int,以便偶尔进行私人审查,当然,工会很棒。但是您似乎想要位域的“实际价值”。

    所以:如果你只在这一个机器/编译器组合上工作,并且你不需要依赖 int 的数学值,只要它有意义,你可以使用工会。但是,如果您可能会移植您的代码,或者如果您需要 int 的“实际值”,则需要编写位操作代码以将位字段放入正确的 int 位中。

    【讨论】:

    • 依赖于实现是指依赖于编译器、依赖于平台还是两者兼而有之?
    • @gsingh2011,两者都有。特定架构的特定编译器可以做它认为最好的事情。
    • @mahesh,不一定。排序是依赖于实现的,所以编译器真的可以做它想做的任何事情。排序可能没有数学意义。联合将为您提供从位字段到整数的一致映射,但您事先不知道这些整数是否是数学值。如果你移植你的代码,每个映射都可能不同。
    • @Mahesh 还值得注意的是,读取最近未写入的联合成员是未定义的行为。我认为大多数编译器都会做你想做的事,但要记住一些事情。
    猜你喜欢
    • 1970-01-01
    • 2021-11-18
    • 1970-01-01
    • 2020-10-30
    • 1970-01-01
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多