5

我知道由于未初始化的填充,memcmp()它不能用于比较尚未达到 0 的结构。memset()但是,在我的程序中,我有一个结构,开始时有几种不同的类型,然后是几十种相同类型,直到结构结束。我的想法是手动比较前几种类型,然后memcmp()在相同类型成员的剩余连续内存块上使用 a 。

我的问题是,C 标准对结构填充有什么保证?我可以在任何或所有编译器上可靠地实现这一点吗?C 标准是否允许在相同类型的成员之间插入结构填充?

我已经实现了我提出的解决方案,它似乎完全按照预期工作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;
}
4

2 回答 2

4

C 标准中对此没有任何保证。从实际的角度来看,它确实是每个当前 C 实现的 ABI 的一部分,并且似乎没有添加填充的目的(例如,它不能用于检查缓冲区溢出,因为允许符合要求的程序写入填充)。但严格来说,它不是“便携的”。

于 2013-12-17T01:08:47.417 回答
0

可悲的是,没有允许您控制结构填充的 C 标准(我听说过)。事实上,像这样初始化的自动分配

struct something val = { 0 };

将导致所有成员val初始化为0. 但是中间的填充留给实现。

您可以使用像 GCC 一样的编译器扩展__attribute__((packed))来消除大部分(如果不是全部)结构填充,但除此之外,您可能会不知所措。

我也知道,如果没有进行重大优化,大多数编译器在大多数情况下都不会费心添加结构填充,这可以解释为什么这在 GCC 下有效。

也就是说,如果您的结构成员导致像这样的奇怪对齐问题

struct something { char onebyte; int fourbyte; }; 

它们将导致编译器在成员之后添加填充onebyte以满足成员的对齐要求fourbyte

于 2013-12-17T01:08:09.160 回答