我有一个预定义的结构(实际上是几个),其中变量跨越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”分割成边界来开展工作,但我不愿意。有什么想法吗?
答案 0 :(得分:17)
我建议不要使用特定于供应商的C语言扩展来匹配设备或网络位格式。即使您使用一系列按供应商的一种语言扩展来排列字段,您仍然需要担心字节顺序,并且您仍然需要一个需要额外指令才能访问的结构布局。
通过使用标准化的C API字符串和内存复制函数以及Posix hton和ntoh函数,您可以编写符合C99标准的程序,该程序可以在任何体系结构或主机上运行,并以最高速度和缓存效率。
一个好的做法是使用已发布标准的以下函数:
C99: memcpy(), Posix: htonl(), htons(), ntohl(), ntohs()
更新:这里有一些代码应该在任何地方都一样。如果Microsoft 仍然没有为C99实现它,或者只是对int size进行通常的假设,则可能需要获得<stdint.h>
from this project。
#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;
}
答案 1 :(得分:7)
位域的对齐和排序是众所周知的特定于实现的。声明一个普通的整数字段并使用掩码和按位(|&amp; ^)运算符操作“位域”是 更安全。
答案 2 :(得分:2)
我不相信Visual Studio中支持此行为。对于包宏的依赖,我尝试使用__declspec(align(1))
并获得相同的行为。我认为你被困在12个字节或稍微重新排序你的结构。
答案 3 :(得分:1)
如果绝对确定需要6个字节然后将其定义为3个短路并自己获取数据......它不会减慢速度......编译器无论如何都要这样做......
答案 4 :(得分:0)
我相信VC ++并不支持这一点,我对GCC在这方面的行为是否实际上是标准的表示严重怀疑。
答案 5 :(得分:0)
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;
}