13

我有以下类型的结构

typedef struct
{
unsigned int a : 8;
unsigned int b : 6;
unsigned int c : 2;
}x, *ptr;

我想做的是改变字段c的值。

我做类似以下的事情

x structure = { 0 };
x->c = 1;

当我查看内存映射时,我希望找到00 01,但我却找到了00 40。看起来在排列第二个字节时,它将c字段放在最低位,将b字段放在最高位。我在 GCC 和 Windows 编译器上都看到了这一点。

现在,我所做的是以下,它工作正常。

unsigned char ptr2 = (unsigned char*) ptr
*(ptr2 + 1)  &= 0xFC
*(ptr2 + 1)  |= 0x01

我看错了内存映射吗?感谢您的帮助。

4

4 回答 4

14

C 标准允许编译器以任何顺序放置位域。没有可靠且可移植的方法来确定顺序。

如果您需要知道确切的位位置,最好使用普通的无符号变量和位掩码。

这是使用位域的一种可能替代方法:

#include <stdio.h>

#define MASK_A    0x00FF
#define MASK_B    0x3F00
#define MASK_C    0xC000
#define SHIFT_A   0
#define SHIFT_B   8
#define SHIFT_C   14

unsigned GetField(unsigned all, unsigned mask, unsigned shift)
{
    return (all & mask) >> shift;
}

unsigned SetField(unsigned all, unsigned mask, unsigned shift, unsigned value)
{
    return (all & ~mask) | ((value << shift) & mask);
}

unsigned GetA(unsigned all)
{
    return GetField(all, MASK_A, SHIFT_A);
}

unsigned SetA(unsigned all, unsigned value)
{
    return SetField(all, MASK_A, SHIFT_A, value);
}

/* Similar functions for B and C here */

int main(void)
{
    unsigned myABC = 0;
    myABC = SetA(myABC, 3);
    printf("%u", GetA(myABC)); // Prints 3
}
于 2013-10-15T08:41:50.393 回答
7

我知道这是一个旧的,但我想补充一下我的想法。

  1. C 中的标头旨在跨对象使用,这意味着编译器必须保持一致。

  2. 根据我的经验,我总是看到 LSB 顺序的位域。这会将位置于 c:b:a 的 MSB->LSB 顺序

以字节顺序读取的 16 位是“00 40”。从 Little-endian 翻译过来,这是一个 16 位的值 0x4000。

这是:

c == [15:14] == b'01
b == [13:8] == 0
a == [7:0] == 0
于 2016-10-13T02:06:03.560 回答
0

内存总是取决于底层机器结构(字节序)和打包/排列编译器正在执行的结构的策略。

于 2013-10-15T08:36:33.057 回答
0

您将 C 结构设置为原始位,后果自负。

您知道这些位是什么以及它们的含义,因此您可以填写结构的字段。是的,它比 memcpy 代码更多,但如果有人添加一个字段,它不会中断,并且如果有助于在通信级别强制执行位级别的特异性。

于 2017-02-21T10:13:39.313 回答