为什么字节顺序位是位域的一个问题? [英] Why bit endianness is an issue in bitfields?

查看:121
本文介绍了为什么字节顺序位是位域的一个问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是位域使用任何便携式code似乎little-和大端平台之间的区别。请参阅linux内核结构iphdr的声明$这样的一个例子C $℃。我不明白为什么字节顺序位是一个问题都没有。

据我了解,位域是纯粹的编译器结构,用于促进位级操作。

例如,请考虑以下位字段:


结构ParsedInt {
    unsigned int类型F1:1;
    unsigned int类型F2:3;
    unsigned int类型F3:4;
};
uint8_t有我;
结构ParsedInt * D =&I;


在这里,写 D-> F2 简直就是(I >> 1)放话说紧凑和可读的方式; (1 LT;&4; - 1)

然而,位操作良好定义并且不管架构的工作。那么,如何来位域是不可移植的?


解决方案

C标准的编译器是免费的存储位域pretty多就是了任何随机的方式。你可以的从不的使那里的位分配的任何假设。这里是未由C标准规定仅有数位字段相关的事情:

不确定的行为


  • 分配给持有位字段(6.7.2.1)的可寻址存储单元的排列。

实现定义的行为


  • 位域能否跨越存储单元边界(6.7.2.1)。

  • 位域的分配单位(6.7.2.1)。
  • 内的顺序

大/小端当然也实现定义。这意味着,您可以结构在以下方面(假设16位整数)进行分配:

  PADDING:8
F1:1
F2:3
F3:4要么PADDING:8
F3:4
F2:3
F1:1要么F1:1
F2:3
F3:4
PADDING:8要么F3:4
F2:3
F1:1
PADDING:8

哪一个应用?以此来猜测,或阅读你的编译器的深入后端文档。添加的32位整数,在大端或小端的复杂性,这一点。然后加入编译器被允许添加任意数量填充的事实的字节您的位字段内的任何地方,因为它是一个结构处理(它不能在结构的最开始添加填充,但在其他地方)。

然后,我还没有提到如果使用普通的整数作为位字段类型=实现定义的行为,如果你使用的任何其他类型的比(符号)INT =实现定义的行为。<会发生什么,或/ p>

因此​​,要回答这个问题,有便携位域code没有这样的事,因为C标准与位域应该如何实现极为模糊。位字段可以被信任的唯一的事情就是为布尔值,其中程序员并不关心位在内存中的位置的块。

唯一的便携式解决方案是使用位运算符,而不是位字段。生成的机器code将是完全一样的,但确定性。位运算符是任何C编译器对于任何系统100%的便携性。

Any portable code that uses bitfields seems to distinguish between little- and big-endian platforms. See the declaration of struct iphdr in linux kernel for an example of such code. I fail to understand why bit endianness is an issue at all.

As far as I understand, bitfields are purely compiler constructs, used to facilitate bit level manipulations.

For instance, consider the following bitfield:

struct ParsedInt {
    unsigned int f1:1;
    unsigned int f2:3;
    unsigned int f3:4;
};
uint8_t i;
struct ParsedInt *d = &i;

Here, writing d->f2 is simply a compact and readable way of saying (i>>1) & (1<<4 - 1).

However, bit operations are well-defined and work regardless of the architecture. So, how come bitfields are not portable?

解决方案

By the C standard, the compiler is free to store the bit field pretty much in any random way it wants. You can never make any assumptions of where the bits are allocated. Here are just a few bit-field related things that are not specified by the C standard:

Unspecified behavior

  • The alignment of the addressable storage unit allocated to hold a bit-field (6.7.2.1).

Implementation-defined behavior

  • Whether a bit-field can straddle a storage-unit boundary (6.7.2.1).
  • The order of allocation of bit-fields within a unit (6.7.2.1).

Big/little endian is of course also implementation-defined. This means that your struct could be allocated in the following ways (assuming 16 bit ints):

PADDING : 8
f1 : 1
f2 : 3
f3 : 4

or

PADDING : 8
f3 : 4
f2 : 3
f1 : 1

or

f1 : 1
f2 : 3
f3 : 4
PADDING : 8

or

f3 : 4
f2 : 3
f1 : 1
PADDING : 8

Which one applies? Take a guess, or read in-depth backend documentation of your compiler. Add the complexity of 32-bit integers, in big- or little endian, to this. Then add the fact that the compiler is allowed to add any number of padding bytes anywhere inside your bit field, because it is treated as a struct (it can't add padding at the very beginning of the struct, but everywhere else).

And then I haven't even mentioned what happens if you use plain "int" as bit-field type = implementation-defined behavior, or if you use any other type than (unsigned) int = implementation-defined behavior.

So to answer the question, there is no such thing as portable bit-field code, because the C standard is extremely vague with how bit fields should be implemented. The only thing bit-fields can be trusted with is to be chunks of boolean values, where the programmer isn't concerned of the location of the bits in memory.

The only portable solution is to use the bit-wise operators instead of bit fields. The generated machine code will be exactly the same, but deterministic. Bit-wise operators are 100% portable on any C compiler for any system.

这篇关于为什么字节顺序位是位域的一个问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆