2015-11-02 31 views
5

我对如何在struct中排序字节有点困惑。结构中的字节顺序

比方说,我有以下结构:

struct container { 
    int myint; 
    short myshort; 
    long mylong; 
}; 

现在,我要初始化struct container类型的变量,就像下面,除了做到使用数组它,我

struct container container1 = {.myint = 0x12345678, 
           .myshort = 0xABCD, 
           .mylong = 0x12345678}; 

假设sizeofintlong4,那的short2

假设没有填充。

那么struct10 bytes的布局如何呢?

它取决于字节顺序吗?

将它像:

0x12345678 ABCD 12345678 

或类似:

0x78563412 CDAB 78563412 

我想要做的是:我有以下的字符数组:

char buffer[10] = {0}; 

我想手动用数据填充该阵列,然后memcpystruct

我应该做[1]

buffer[0] = 0x12345678 & 0xFF; 
buffer[1] = 0x12345678 >> 8 & 0xFF; 
buffer[2] = 0x12345678 >> 16 & 0xFF; 
buffer[3] = 0x12345678 >> 24 & 0xFF; 
... 
buffer[9] = 0x12345678 >> 24 & 0xFF; 

还是应[2]

buffer[0] = 0x12345678 >> 24 & 0xFF; 
buffer[1] = 0x12345678 >> 16 & 0xFF; 
buffer[2] = 0x12345678 >> 8 & 0xFF; 
buffer[3] = 0x12345678 & 0xFF; 
... 
buffer[9] = 0x12345678 & 0xFF; 

我做之前,我memcpy像:

memcpy(&container1, buffer, sizeof(container1); 

而且,如果我是wr到一个数组并复制到struct,它是否跨系统可移植,特别是关于字节序?

编辑: 在大端确实有点endian机器和[2][1]工作?

+5

不,这是不可移植。是的,这取决于排序。而有关填充和类型大小的假设也会导致可移植性问题。 – user3386109

+0

为了强调*不可移植的方式*,这意味着在同一个操作系统上从编译器到编译器都不是可移植的方式,从操作系统到操作系统的便携性更小。 –

+0

当然这取决于字节顺序!在“没有填充”假设之后,问题不再与结构类型有关。它只是关于在内存中表示整数。 – AnT

回答

2

它取决于字节顺序吗?

是的,它取决于机器的字节顺序。所以你的逻辑会根据机器的字节顺序而改变。

还有没有便携的方式*这样做是因为结构填充。虽然不同的编译器确实提供了禁用结构填充的自定义方法。检查Force C++ struct to not be byte aligned

  • 您可以添加一个static_assert(需要C11支持)刚好以确保您的代码不会编译除非你的结构是排列紧密。你不会有可移植的代码,但你仍然可以确定,如果你的代码编译,它会表现正确。

    static_assert(sizeof(container) == sizeof(int) + sizeof(short) + sizeof(long)); 
    
+0

不同编译器提供的禁用结构填充的方法不可移植 - 每个编译器都有自己的方法,除非它正在模拟其他方面的兼容性。您可能需要注意'static_assert'需要一个C11编译器(或符合C99或C90的编译器中的非标准扩展)。 –

+0

@JonathanLeffler我已经提到过,在我的回答以及我已经链接的问题的答案中,提到OP寻求的解决方案不可移植。编辑以进一步强调它。 – bashrc

+2

我在C语言问题中混合了关于链接到仅用于C++的问题的观点。这至少是一个警告标志。 –

1

还有一个问题,你的结构元素内对齐的。

您的结构有缺口用于对齐。真正的布局是,如果你做的事:关于使用union

struct container { 
    int myint; 
    short myshort; 
    char __pad__[2]; // padding to align mylong to 4/8 byte boundary 
    long mylong; 
}; 

什么:

union { 
    struct container vals; 
    char buf[10]; 
}; 

但是,为什么做你想做的事吗?对于我能想到的几乎任何场景,可能都有更清晰的方法来获得效果。

当你说数组,你的意思是你想要初始化你的结构数组吗?这是可以做到:

struct container conts[3] = { 
    { .myint = 1, .myshort = 2, .mylong = 3 }, 
    { .myint = 4, .myshort = 5, .mylong = 6 }, 
    { .myint = 7, .myshort = 8, .mylong = 9 } 
}; 

BTW,有的方式在C++做static_assert

// compile time assertion -- if the assertion fails, we will get two case 0:'s 
// which will cause the compiler to flag this 
#define static_assert(_assert) \ 
    do { \ 
     switch (0) { \ 
     case (_assert): \ 
      break; 
     case 0: \ 
      break; \ 
     } \ 
    } while (0) 
+0

而不是'char buf [10];',更好的使用'char buf [sizeof(struct container)];'。 – alk