我正在尝试构建自己的库,用于在不同字节序列的整数和签名表示之间进行转换。部分原因是直接访问char缓冲区作为相同大小的整数(主要用于快速比较)。我非常担心这个项目的可移植性。我希望这个库可以在所有机器和新旧编译器上使用,而不仅仅是linux上的gcc或clang。
最初我使用整数成员的c99固定宽度整数类型。& nbsp这个工作正常。& nbsp当我从固定宽度整数切换到相同大小的位字段时问题就开始了。我这样做是为了通过不依赖于c99功能来提高可移植性。& nbsp
问题是,当我使用位字段时,gcc会抱怨插入了填充(-Werror和-Wpadded传递给gcc):
错误:将结构大小填充到对齐边界
以下是其中一个工会的例子:
旧版本,工作正常:
typedef union
{
unsigned char bytes[4];
uint32_t uvalue;
} upicl_uint32_be;
新版本,添加不需要的填充:
typedef union
{
unsigned char bytes[4];
unsigned long uvalue : 32;
} upicl_uint32_be;
当32位位字段已经对齐时,我不知道为什么会在我的工会中添加填充。
有更好的方法吗?
答案 0 :(得分:1)
可能long
长度为8个字节,因此位域将占用8个字节,因为它与uint32_t
的大小不同。
联合类型的名称表明您希望位域基于uint32_t
而不是unsigned long
(或者您认为两者是相同的,这显然是不正确的)。
答案 1 :(得分:0)
您好像是在64位系统上编译代码,否则unsigned long
将与uint32_t
相同。您可以测试以下内容:
typedef union {
uint32_t uvalue : 1;
} upicl_uint32_be;
...也发出警告。问题是你只有1位数据,但uint32_t
强制它占用32位。
如果您不想收到警告,请使用unsigned int
类型。实际上,除了一些微控制器unsigned int
之外的所有系统都保证是32位。但在我看来,使用uint32_t
是最好的选择,因为它始终保证是32位。
您可以编写一些#define
黑客,看看哪种基本类型是32位,但我不推荐这样的黑客攻击。考虑到C99已超过15年,所以几乎所有编译器都支持它。
答案 2 :(得分:0)
假设您需要一个4字节无符号长本机,您可以使用对齐语法来设置它。
typedef union
{
unsigned long unused : 0;
unsigned char bytes[4];
unsigned long uvalue : 32;
} upicl_uint32_be;
可能会成功。
另一种可能性就是颠倒顺序,以便编译器首先看到unsigned long。
typedef union
{
unsigned long uvalue : 32;
unsigned char bytes[4];
} upicl_uint32_be;
尝试双打的最后一件事通常是8字节
typedef union
{
double unused;
unsigned char bytes[4];
unsigned long uvalue : 32;
} upicl_uint32_be;