C工会结果出乎意料

问题描述 投票:0回答:1

此代码未按我的预期返回,标识符应为 0xABC 是否可以解决此问题?

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

typedef struct {
    union {
        struct {
            uint8_t address: 8;
            uint16_t identifier: 16;
        };
        uint32_t fullAddress;
    };
} isotpAddress_t;

int main() {
    isotpAddress_t myAddress;
    
    myAddress.fullAddress = 0xABCDE;
    printf("Address: 0x%02X\n", myAddress.address);       // Output: Address: 0xDE
    printf("Identifier: 0x%04X\n", myAddress.identifier);  // Output: Identifier: 0x000A but want 0x0ABC

    return 0;
}

输出:

> Address: 0xDE
> Identifier: 0x000A
c union
1个回答
0
投票

结构中位域的布局很大程度上是由实现定义的。话虽这么说,这就是可能发生的事情。

    struct {
        uint8_t address: 8;
        uint16_t identifier: 16;
    };

实现通常会使用位域的基本类型作为一个或多个位域的存储单元。如果两个位域的基本类型相同并且有足够的空间,那么它们通常会被放入同一个存储单元中。

在上面的情况下,第一个位字段用尽了它所包含的整个

uint8_t
存储单元。下一个位字段位于
uint16_t
存储单元中,因此在它之前可能有 1 个字节的填充以进行正确对齐。这就是你的“丢失”字节所在的位置。

如果将位域的基本类型更改为

uint32_t
,则两者很可能位于同一存储单元中,并且它们之间没有填充。

    struct {
        uint32_t address: 8;
        uint32_t identifier: 16;
    };

通过此更改,在 CentOS 7 上使用 gcc 4.8.5 进行编译,我能够得到您想要的结果。但同样,这个结果是由实现定义的。不能保证这适用于所有实现。

© www.soinside.com 2019 - 2024. All rights reserved.