簡體   English   中英

使用memcmp()和指針算法比較C中的結構

[英]Compare structs in C using memcmp() and pointer arithmetic

我知道memcmp()由於未初始化的填充而不能用於將尚未被memset()結構比較為0。 但是,在我的程序中,我的結構開頭有幾種不同的類型,然后有幾十種相同類型直到結構結束。 我的想法是手動比較前幾種類型,然后在相同類型成員的其余連續內存塊上使用memcmp()

我的問題是,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;
}

C標准中對此不做任何保證。 從實際的角度來看,對於每個當前的C實現,它確實是ABI的一部分,並且似乎沒有任何添加填充的目的(例如,不能將其用於檢查緩沖區溢出,因為允許一致性程序向其中寫入內容)。填充)。 但是嚴格來說,它不是“便攜式”的。

遺憾的是,沒有C標准(我聽說過)可以控制結構填充。 事實是這樣初始化的自動分配

struct something val = { 0 };

將導致val所有成員都初始化為0 但是介於兩者之間的填充留給實現。

您可以使用一些編譯器擴展,例如GCC的__attribute__((packed))來消除大部分(即使不是全部)結構填充,但除此之外,您可能會一頭霧水。

我也知道,如果沒有進行重大優化,大多數編譯器在大多數情況下都不會添加結構填充,這可以解釋為什么它在GCC下有效。

也就是說,如果您的結構成員導致像這樣的奇怪對齊問題

struct something { char onebyte; int fourbyte; }; 

它們會導致編譯器的后添加填充onebyte構件滿足的對准要求fourbyte構件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM