c - Linux (gcc) 和 Windows (mingw32 gcc) 之间具有不同位域的结构大小

标签 c windows gcc struct bit-fields

类似的问题,但特定于打包结构: Why would the size of a packed structure be different on Linux and Windows when using gcc?


我正在为 Linux 和 Windows 构建一个共享库,它需要通过网络连接处理结构良好的数据。我在 Linux 上使用 gcc 4.8.2,并使用 i686-pc-mingw32-gcc 4.8.1 为 Windows 目标交叉编译。

我制作了这个小程序来演示这个问题(请注意 GCC 属性已被注释掉,保留它们以供引用):

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

typedef uint16_t word_t;

typedef enum //__attribute__((__packed__))
{
  PRIO_0 = 0,
  PRIO_1,
  PRIO_2,
  PRIO_3,
  PRIO_4,
  PRIO_5,
  PRIO_6,
  PRIO_7,
}
prio_t;

typedef enum //__attribute__((__packed__))
{
  FLAG_A = 0,
  FLAG_B,
}
flag_t;

typedef struct //__attribute__((__packed__))
{
  word_t id     : 8;
  prio_t prio   : 3;
  flag_t flag_1 : 1;
  flag_t flag_2 : 1;
  flag_t flag_3 : 1;
  flag_t flag_4 : 1;
  word_t spare  : 1;
}
recd_t;


int main(int argc, char *argv[])
{
#define NAME_WIDTH 32

  printf("%-*s = %lu\n", NAME_WIDTH, "sizeof(prio_t)", (unsigned long)sizeof(prio_t));
  printf("%-*s = %lu\n", NAME_WIDTH, "sizeof(flag_t)", (unsigned long)sizeof(flag_t));
  printf("%-*s = %lu\n", NAME_WIDTH, "sizeof(recd_t)", (unsigned long)sizeof(recd_t));

  return 0;
}

我正在为 Linux 编译使用: gcc -g -Wall test.c -o ./test

和Windows: i686-pc-mingw32-gcc -g -Wall test.c -o ./test.exe

我觉得很简单。在 Linux 上运行时,输出是我所期望的:

sizeof(prio_t)                   = 4
sizeof(flag_t)                   = 4
sizeof(recd_t)                   = 4

但是在 Windows 上:

sizeof(prio_t)                   = 4
sizeof(flag_t)                   = 4
sizeof(recd_t)                   = 12

那么 Windows 大小有什么关系呢?为什么在这种情况下它们与 Linux 不同?


我最终需要打包这些枚举和结构,但这个问题在任何打包完成之前就出现了。但是,启用后,结果是相似的:

Linux:

sizeof(prio_t)                   = 1
sizeof(flag_t)                   = 1
sizeof(recd_t)                   = 2

Windows :

sizeof(prio_t)                   = 1
sizeof(flag_t)                   = 1
sizeof(recd_t)                   = 6

最佳答案

C 规范有一个信息性附件 (Annex J),它总结了未指定的行为、未定义的行为和实现定义的行为。这是关于位域的内容。

J.3 Implementation-defined behavior

A conforming implementation is required to document its choice of behavior in each of the areas listed in this subclause. The following are implementation-defined:

J.3.9 Structures, unions, enumerations, and bit-fields

  • Whether a "plain" int bit-field is treated as a signed int bit-field or as an unsigned int bit-field (6.7.2, 6.7.2.1).

  • Allowable bit-field types other than _Bool, signed int, and unsigned int (6.7.2.1).

  • Whether atomic types are permitted for bit-fields (6.7.2.1).
  • 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).
  • The alignment of non-bit-field members of structures (6.7.2.1). This should present no problem unless binary data written by one implementation is read by another.
  • The integer type compatible with each enumerated type (6.7.2.2).

您可以得出自己的结论,但我不会在可移植的代码中使用位域。


似乎在 Windows 上,每次类型更改时,编译器都会启动一个新的“单元”。因此,在未打包的情况下,您有一个 word_t(2 个字节),然后是一个 prio_t(4 个字节)、一个 flag_t(4 个字节)和另一个 word_t(2 个字节),总共 12 个字节。打包后为 2,1,1,2,总共 6 个。如果您将所有字段声明为 uint16_t,您可能会在 Windows 上获得正确的大小,但您仍然有 “顺序的问题单元内位域的分配” 是实现定义的。

关于c - Linux (gcc) 和 Windows (mingw32 gcc) 之间具有不同位域的结构大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31349819/

相关文章:

c - 您如何获得指向 .text 部分的指针?

c - 如何在C中获取指针的实际地址?

windows - EC2 : cannot open port 5080 on windows instance

windows - 为什么我不能将 DIB 部分放入剪贴板?

python - 无法找到或加载 Qt 平台插件 "windows"-- cx_freeze(.exe)

c - 数字打印为负值,但以某种方式测试为正值

c++ - Clang 编译有效,而 gcc 不适用于菱形继承(钻石问题)

gcc - 为什么gcc "start"函数(在main之前)中有无意义的asm代码?

GCC:-static 和 -pie 与 x86 不兼容?

c - 使用 ATMEGA168 测量时间