我希望 C 结构的大小是 16 个字节(16B/32B/48B/..)的倍数。它的大小无关紧要。它只需要是 16 个字节的倍数。
我怎么能强制编译器这样做呢?
对于 Microsoft Visual C++:
#pragma pack(push, 16)
struct _some_struct
{
...
}
#pragma pack(pop)
对于海湾合作委员会:
struct _some_struct { ... } __attribute__ ((aligned (16)));
例子:
#include <stdio.h>
struct test_t {
int x;
int y;
} __attribute__((aligned(16)));
int main()
{
printf("%lu\n", sizeof(struct test_t));
return 0;
}
gcc -o main main.c
用将输出编译16
。其他编译器也是如此。
C 结构的大小取决于结构的成员、它们的类型以及它们的数量。实际上没有标准的方法来强制编译器使结构成为某个大小的倍数。一些编译器提供了一个编译指示,允许您设置对齐边界,但这确实是另一回事。并且可能有一些会有这样的设置或提供这样的 pragma。
但是,如果您坚持使用这种方法,那就是对结构进行内存分配并强制内存分配向上舍入到下一个 16 字节大小。
因此,如果您有这样的结构。
struct _simpleStruct {
int iValueA;
int iValueB;
};
然后,您可以执行以下操作。
{
struct _simpleStruct *pStruct = 0;
pStruct = malloc ((sizeof(*pStruct)/16 + 1)*16);
// use the pStruct for whatever
free(pStruct);
}
就您而言,这将把大小推高到下一个 16 字节大小。然而,内存分配器所做的可能是也可能不是给你一个实际上是那个大小的块。内存块实际上可能比您的请求大。
如果您要对此做一些特殊的事情,例如,假设您要将此结构写入文件并且您想知道块大小,那么您将不得不进行与 malloc() 中使用的相同的计算,而不是而不是使用 sizeof() 运算符来计算结构的大小。
所以接下来的事情是使用宏编写自己的 sizeof() 运算符,例如。
#define SIZEOF16(x) ((sizeof(x)/16 + 1) * 16)
据我所知,没有可靠的方法可以从指针中提取已分配块的大小。通常,指针将有一个内存分配块,由内存堆管理函数使用,该函数将包含各种内存管理信息,例如分配的块大小实际上可能大于请求的内存量。然而,这个块的格式以及它相对于提供的实际内存地址的位置将取决于 C 编译器的运行时间。
这完全取决于编译器和其他工具,因为在 ISO C 标准中没有详细说明对齐(它指定对齐可能在编译器的要求下发生,但没有详细说明如何强制执行它)。
您需要查看编译器工具链的特定于实现的东西。它可能会提供一个#pragma pack
(或align
其他一些东西),您可以将其添加到您的结构定义中。
它也可以将其作为语言扩展提供。例如,gcc 允许您向定义添加属性,其中之一控制对齐:
struct mystruct { int val[7]; } __attribute__ ((aligned (16)));
您也许可以做一个双重结构,将您的实际结构包装在第二个可以添加填充的结构中:
struct payload {
int a; /*Your actual fields. */
float b;
char c;
double d;
};
struct payload_padded {
struct payload p;
char padding[16 * ((sizeof (struct payload) + 15) / 16)];
};
然后你可以使用填充结构:
struct payload_padded a;
a.p.d = 43.3;
当然,您可以利用结构的第一个成员从结构开始的 0 字节开始这一事实,并将指针struct payload_padded
视为指向 a 的指针struct payload
(因为它是):
float d_plus_2(const struct payload *p)
{
return p->d + 2;
}
/* ... */
struct payload_padded b;
const double dp2 = d_plus_2((struct payload *) &b);