我知道由于未初始化的填充,memcmp()
不能用于比较未memset()
到0的结构。但是,在我的程序中,我有一个结构,在开始时有几个不同的类型,然后是几十个相同的类型,直到结构的结尾。我的想法是手动比较前几种类型,然后在相同类型成员的剩余连续内存块上使用memcmp()
。
我的问题是,C标准对结构填充有什么保证?我可以在任何或所有编译器上可靠地实现这一点吗? C标准是否允许在相同类型的成员之间插入struct padding?
我已经实现了我提出的解决方案,它似乎与gcc
完全一致:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
struct foo
{
char a;
void *b;
int c;
int d;
int e;
int f;
};
static void create_struct(struct foo *p)
{
p->a = 'a';
p->b = NULL;
p->c = 1;
p->d = 2;
p->e = 3;
p->f = 4;
}
static int compare(struct foo *p1, struct foo *p2)
{
if (p1->a != p2->a)
return 1;
if (p1->b != p2->b)
return 1;
return
/* Note the typecasts to char * so we don't get a size in ints. */
memcmp(
/* A pointer to the start of the same type members. */
&(p1->c),
&(p2->c),
/* A pointer to the start of the last element to be compared. */
(char *)&(p2->f)
/* Plus its size to compare until the end of the last element. */
+sizeof(p2->f)
/* Minus the first element, so only c..f are compared. */
-(char *)&(p2->c)
) != 0;
}
int main(int argc, char **argv)
{
struct foo *p1, *p2;
int ret;
/* The loop is to ensure there isn't a fluke with uninitialized padding
* being the same.
*/
do
{
p1 = malloc(sizeof(struct foo));
p2 = malloc(sizeof(struct foo));
create_struct(p1);
create_struct(p2);
ret = compare(p1, p2);
free(p1);
free(p2);
if (ret)
puts("no match");
else
puts("match");
}
while (!ret);
return 0;
}
答案 0 :(得分:4)
在C标准中无法保证这一点。从实际的角度来看,它是每个当前C实现的ABI的一部分,并且似乎没有添加填充的目的(例如,它不能用于检查缓冲区溢出,因为允许一致的程序写入填充)。但严格来说,这不是“便携式”。
答案 1 :(得分:0)
可悲的是,没有C标准(我听说过)允许您控制结构填充。事实上,像这样初始化的自动分配
struct something val = { 0 };
会导致val
中的所有成员初始化为0
。但其间的填充留待实现。
您可以使用GCC __attribute__((packed))
之类的编译器扩展来消除大多数(如果不是全部)结构填充,但除此之外您可能会感到茫然。
我也知道,如果没有进行大的优化,大多数编译器都不会在大多数情况下添加结构填充,这可以解释为什么它在GCC下工作。
那就是说,如果您的结构成员导致像这样的奇怪的对齐问题
struct something { char onebyte; int fourbyte; };
它们将使编译器在onebyte
成员之后添加填充以满足fourbyte
成员的对齐要求。