简体   繁体   English

C/C++ 位域字节序在实际应用中真的是个问题吗?

[英]C/C++ Is bitfield endianess really a problem in actual practice?

So per the C compiler standard here:所以根据这里的 C 编译器标准:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

We find a failure to pin down requirements for exactly how bit-fields get implemented inside a C compiler.我们发现未能确定位域如何在 C 编译器中实现的确切要求。 Apparently, as long as the bit-fields behave like any other scalar field, anything goes.显然,只要位域表现得像任何其他标量域,一切都会发生。 The doc section 6.7.2.1-10 says:文档部分 6.7.2.1-10 说:

"An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified." “一个实现可以分配任何足够大的可寻址存储单元来容纳一个位域。如果有足够的空间,紧跟在结构中另一个位域之后的位域应被打包到同一单元的相邻位中。如果空间不足空间保留,不适合的位字段是否放入下一个单元或与相邻单元重叠是实现定义的。单元内位字段的分配顺序(高阶到低阶或低阶到高阶)是实现定义的。未指定可寻址存储单元的对齐方式。”

This looming freedom for the compiler seems to be a full-stop for many who claim "you cannot trust bit-fields", or "bit-fields are not portable."对于许多声称“您不能信任位域”或“位域不可移植”的人来说,这种迫在眉睫的编译器自由似乎是句号。 The alarm suggests a whole herd of compiler writers and CPU makers conspiring in a star chamber, just grinning and anxious to do some exotic bit-field sizing and alignments simply because the standard permits.警报表明,一大群编译器编写者和 CPU 制造者在一个星室中密谋,只是因为标准允许而咧嘴笑着急于做一些奇异的位域大小和对齐。

WHERE IS THE EVIDENCE for these crazy bohemian compiler/CPU designers who are dedicated to guaranteeing that bit-fields remain forever undependable and unportable?对于这些致力于保证位域永远不可靠和不可移植的疯狂波西米亚式编译器/CPU 设计师来说,证据在哪里? I want to see actual hard evidence of the green-men on mars.我想看到火星上绿人的实际确凿证据。

I've attached straightforward C++ source code to tell the bit-field truth about any system with a C++ compiler.我附上了简单的 C++ 源代码来告诉任何带有 C++ 编译器的系统的位域真相。 I am asking the community, NOT for opinion, but for hard output evidence for your system and compiler if it diverges from the results posted.我在问社区,不是征求意见,而是如果你的系统和编译器与发布的结果不同,那么它的硬输出证据。 If I had the ability to poll the entire C/C++ community for same/not-same vote compared to the posted results, I wonder what the percentages would be?如果我有能力对整个 C/C++ 社区进行与发布的结果相比相同/不同的投票,我想知道百分比是多少?

#include <stdio.h>

/*
 A simple program to illustrate the bitfields actual internal compiled layout.
 Results depend on machine architecture and compiler implementation and flags.
*/

typedef unsigned long long int ulli;

struct bitf
{
    //   field      bits  offset
    ulli f0         : 1; // 0
    ulli f1         : 2; // 1
    ulli f3         : 3; // 3
    ulli f7         : 4; // 6
    ulli f15        : 5; // 10
    ulli f31        : 6; // 15
    ulli f63        : 7; // 21
    ulli f127       : 8; // 28
    ulli f255       : 9; // 36
    ulli f511       :10; // 45
    ulli end        : 9; // 55
                         // 64

    bitf():
         f0         ( 0 )
        ,f1         ( 1 )
        ,f3         ( 3 )
        ,f7         ( 7 )
        ,f15        ( 15 )
        ,f31        ( 31 )
        ,f63        ( 63 )
        ,f127       ( 127 )
        ,f255       ( 255 )
        ,f511       ( 511 )
        ,end        ( 0 )
    {}

    ulli get_shft() const
    {
        ulli bits=0;
        bits <<= 9; bits |=   0;
        bits <<=10; bits |= 511;
        bits <<= 9; bits |= 255;
        bits <<= 8; bits |= 127;
        bits <<= 7; bits |=  63;
        bits <<= 6; bits |=  31;
        bits <<= 5; bits |=  15;
        bits <<= 4; bits |=   7;
        bits <<= 3; bits |=   3;
        bits <<= 2; bits |=   1;
        bits <<= 1; bits |=   0;
        return bits;
    }

    ulli get_cast() const
    {
        ulli bits = *((ulli*)(this));
        return bits;
    }
};

int main()
{
    bitf bf;
    ulli shft = bf.get_shft();
    ulli cast = bf.get_cast();

    printf("sizeof(ulli) is %zu\n\n",sizeof(ulli));
    printf("shft%scast\n\n",(shft==cast)?"==":"!=");
    printf("BITS from MSB 63 (left) down to LSB 0 (right)\n");
    printf("    : "); for(int i=63; i>=0; i--) printf("%c",(i%10)==0 ? i/10 +'0' : ' '); printf("\n");
    printf("    : "); for(int i=63; i>=0; i--) printf("%d",i%10); printf("\n");
    printf("shft: "); for(int i=63; i>=0; i--) printf("%llu",(shft>>i)&1); printf("\n");
    printf("cast: "); for(int i=63; i>=0; i--) printf("%llu",(cast>>i)&1); printf("\n");
    printf("    : ====----====----====----====----====----====----====----====----\n");
    printf("shft: "); for(int i=15;i>=0;i--) printf("%4llx",(shft>>(i*4)&0xf)); printf("\n");
    printf("cast: "); for(int i=15;i>=0;i--) printf("%4llx",(cast>>(i*4)&0xf)); printf("\n");
    printf("    : ====----====----====----====----====----====----====----====----\n");
    unsigned char *pb;
    pb = (unsigned char*)(&shft);
    printf("shft: "); for(int i=sizeof(shft)-1; i>=0; i--) printf("%8x", pb[i]); printf("\n");
    pb = (unsigned char*)(&cast);
    printf("cast: "); for(int i=sizeof(cast)-1; i>=0; i--) printf("%8x", pb[i]); printf("\n");
    printf("\n");

    printf("<ENTER>"); getchar();
    return 0;
}

Results for Intel Core i7, Win10, VS2015, 64bit build英特尔酷睿 i7、Win10、VS2015、64 位版本的结果

sizeof(ulli) is 8

shft==cast

BITS from MSB 63 (left) down to LSB 0 (right)
    :    6         5         4         3         2         1         0
    : 3210987654321098765432109876543210987654321098765432109876543210
shft: 0000000000111111111011111111011111110111111011111011110111011010
cast: 0000000000111111111011111111011111110111111011111011110111011010
    : ====----====----====----====----====----====----====----====----
shft:    0   0   3   f   e   f   f   7   f   7   e   f   b   d   d   a
cast:    0   0   3   f   e   f   f   7   f   7   e   f   b   d   d   a
    : ====----====----====----====----====----====----====----====----
shft:        0      3f      ef      f7      f7      ef      bd      da
cast:        0      3f      ef      f7      f7      ef      bd      da

<ENTER>

One common way that bitfields can differ is in bit endianness.位域可以不同的一种常见方式是位字节序。 Little endian machine will have the low order bits first while big endian machines have the high order bits first.小端机器先有低位,而大端机器先有高位。

As an example, here is the definition of struct iphdr , which models an IP header, taken from /usr/include/netinet/ip.h on a CentOS 7.2 system:例如,这里是struct iphdr的定义,它模拟了一个 IP 标头,取自 CentOS 7.2 系统上的 /usr/include/netinet/ip.h:

struct iphdr
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    unsigned int ihl:4;
    unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
    unsigned int version:4;
    unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
    u_int8_t tos;
    u_int16_t tot_len;
    u_int16_t id;
    u_int16_t frag_off;
    u_int8_t ttl;
    u_int8_t protocol;
    u_int16_t check;
    u_int32_t saddr;
    u_int32_t daddr;
    /*The options start here. */
  };

This struct is meant to be layered directly on top of a buffer containing a raw IP datagram at the point the IP header starts.该结构旨在直接分层在包含原始 IP 数据报的缓冲区的顶部,该缓冲区位于 IP 标头开始处。 Note that the ordering of the version and ihl fields differ depending on the endianness.请注意, versionihl字段的顺序因字节顺序而异。

And in reference to this:并参考此:

a whole herd of compiler writers and CPU makers conspiring in a star chamber, just grinning and anxious to do some exotic bit-field sizing and alignments simply because the standard permits.一大群编译器编写者和 CPU 制造者在一个星室里密谋,只是因为标准允许而咧着嘴笑着急于做一些奇特的位域大小和对齐。

Compiler writers are indeed quick to take advantage of any behavior undefined or unspecified by the standard in order to perform a wide variety of optimizations that might surprise those that think C always behaves as a thin wrapper around assembly language.编译器编写者确实很快就会利用标准中未定义或未指定的任何行为来执行各种优化,这些优化可能会让那些认为 C 始终表现为汇编语言的瘦包装器的人感到惊讶。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM