簡體   English   中英

C ++ struct alignment問題

[英]C++ struct alignment question

我有一個預定義的結構(實際上是幾個),其中變量跨越32位字邊界。 在Linux(以及使用GCC的Windows)中,我能夠使用'attribute((packed))'將我的結構打包到正確的大小。 但是我無法使用VC ++和#pragma pack以相同的方式工作。

使用GCC,返回正確的6字節大小:

struct
{
    unsigned int   a                : 3;
    unsigned int   b                : 1;
    unsigned int   c                : 15;
    unsigned int   troubleMaker     : 16;
    unsigned short padding          : 13;
} __attribute__((packed)) s;

使用VC ++,這將返回不正確的8字節大小

#pragma pack(push)
#pragma pack(1)

struct
{
    unsigned int   a                : 3;
    unsigned int   b                : 1;
    unsigned int   c                : 15;
    unsigned int   troubleMaker     : 16;
    unsigned short padding          : 13;
} s;

#pragma pack(pop)

我可以通過手動將“troubleMaker”分割成邊界來實現工作,但我不願意。 有任何想法嗎?

瘋狂的想法:首先編寫一個符合C99或C ++ 03的程序


我建議不要使用特定於供應商的C語言擴展來匹配設備或網絡位格式。 即使您使用一系列每個供應商的語言擴展來排列字段,您仍然需要擔心字節順序,並且您仍然需要一個需要額外指令才能訪問的結構布局。

您可以使用標准化的C API字符串和內存復制函數以及Posix hton和ntoh函數編寫符合C99標准的程序,該程序可以在任何體系結構或主機上以最高速度和緩存效率運行。

一個好的做法是使用已發布標准的以下函數:

C99: memcpy(), Posix: htonl(), htons(), ntohl(), ntohs()

更新:這里有一些代碼應該在任何地方都一樣。 如果Microsoft 仍然沒有為C99實現它,或者只是對int size做出通常的假設,那么你可能需要從這個項目中獲取<stdint.h>

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>

struct packed_with_bit_fields {  // ONLY FOR COMPARISON
    unsigned int   a        : 3;
    unsigned int   b        : 1;
    unsigned int   c        : 15;
    unsigned int   troubleMaker : 16;
    unsigned short padding  : 13;
} __attribute__((packed));       // USED ONLY TO COMPARE IMPLEMENTATIONS

struct unpacked { // THIS IS THE EXAMPLE STRUCT
    uint32_t a;
    uint32_t b;
    uint32_t c;
    uint32_t troubleMaker;
}; // NOTE NOT PACKED

struct unpacked su;
struct packed_with_bit_fields sp;
char *bits = "Lorem ipsum dolor";

int main(int ac, char **av) {
  uint32_t x;   // byte order issues ignored in both cases

  // This should work with any environment and compiler
  memcpy(&x, bits, 4);
  su.a = x & 7;
  su.b = x >> 3 & 1;
  su.c = x >> 4 & 0x7fff;
  memcpy(&x, bits + 2, 4);
  su.troubleMaker = x >> 3 & 0xffff;

  // This section works only with gcc
  memcpy(&sp, bits, 6);
  printf( sp.a == su.a
      &&  sp.b == su.b
      &&  sp.c == su.c
      &&  sp.troubleMaker == su.troubleMaker
      ? "conforming and gcc implementations match\n" : "huh?\n");
  return 0;
}

位域的對齊和排序是眾所周知的特定於實現的。 它是安全聲明一個正常的整型字段,並使用口罩和位內操縱“位域”(|&^)運營商。

我不相信Visual Studio中支持此行為。 在對包宏的依賴中,我嘗試使用__declspec(align(1))並獲得了相同的行為。 我認為你被困在12個字節或者重新排序你的結構。

我相信VC ++不支持這一點,我對GCC在這方面的行為是否實際上是標准的表示嚴重懷疑。

如果絕對確定需要6個字節然后將其定義為3個短路並自己獲取數據...它不會減慢速度......編譯器就是這樣做...

只有符合規范的代碼的較短示例


struct unpacked {  // apparently my other example was too long and confusing
    uint32_t a;    // ...here is a much shorter example with only the conforming
    uint32_t b;    // ...code. (The other program had the gcc-specific declaration,
    uint32_t c;    // but only for test code. Still, it was a bit long.)
    uint32_t troubleMaker;
};

struct unpacked su;
char *bits = "Lorem ipsum dolor";

void f(void) {
  uint32_t x;

  memcpy(&x, bits, 4);
  su.a = x & 7;
  su.b = x >> 3 & 1;
  su.c = x >> 4 & 0x7fff;
  memcpy(&x, bits + 2, 4);
  su.troubleMaker = x >> 3 & 0xffff;
  return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM