[英]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.