如何在标准C中比较两个结构体实例的相等性?
C语言没有提供相关的语言特性来实现此功能 - 你需要自己逐个比较每个结构体成员。
memcmp(&a, &b, sizeof(struct foo))
,但在某些情况下可能无法正常工作。编译器可能会为结构添加对齐缓冲区空间,并且位于缓冲区空间中的内存位置上的值不能保证是任何特定的值。calloc
或memset
分配结构体的完整大小,那么您可以使用memcmp
进行浅层比较(如果您的结构包含指针,则仅当指针所指向的地址相同时才匹配)。memcmp
进行浅层比较,前提是先清除内存。这个回答接近于正确,但并不完全正确。当然,问题也没有定义“相等”,所以如果你认为“相等”意味着“对象表示的逐字节相等”,那么memcmp
正好做到了这一点(无论内存是否被清除)。 - Steve Jessop如果您经常这样做,我建议编写一个比较两个结构的函数。这样,如果您改变了结构,您只需要在一个地方更改比较函数。
至于如何完成它... 您需要逐个比较每个元素。
你不能使用memcmp函数来比较结构体的相等性,因为在结构体字段之间可能存在随机填充字符。
// bad
memcmp(&struct1, &struct2, sizeof(struct1));
typedef struct Foo {
char a;
/* padding */
double d;
/* padding */
char e;
/* padding */
int f;
} Foo ;
你必须使用成员逐一比较才能确保安全。
@Greg 正确地指出在一般情况下需要编写明确的比较函数。
如果满足以下条件,则可以使用memcmp
:
NaN
的浮点字段。-Wpadded
检查)或者结构体在初始化时显式使用memset
进行了初始化。BOOL
),其具有不同但等效的值。除非您正在为嵌入式系统编程(或编写可能在其中使用的库),否则我不会担心C标准中的某些边角情况。在任何32位或64位设备上都不存在近指针与远指针区别。我所知道的没有非嵌入式系统拥有多个NULL
指针。
另一个选择是自动生成相等函数。如果以简单方式布置您的结构定义,那么可以使用简单的文本处理来处理简单的结构定义。对于一般情况,可以使用libclang - 因为它使用与Clang相同的前端,所以它能正确处理所有边角情况(除了错误)。
我还没有看到这样的代码生成库。但是,它似乎相对简单。
然而,这样生成的相等函数在应用程序级别上经常做错事。例如,在Windows中,应该浅层还是深层比较两个UNICODE_STRING
结构?
memset
等显式初始化结构体并不能保证在进一步写入结构体元素后填充位的值,参见:https://dev59.com/5q7la4cB1Zd3GeqPlOoA。 - gengkev请注意,只要您不同时初始化所有成员变量,就可以放心地在非静态结构上使用memcmp(),而不必担心填充问题。这是C90定义的:
memcmp
函数不会比较结构体本身,而是比较它们的二进制数据。由于结构体中可能存在垃圾数据,因此使用memcmp
函数进行比较时往往会得到错误的结果。
逐个比较结构体元素可以保证比较的准确性和安全性。
int my_struct_cmp(const struct my_struct * lhs, const struct my_struct * rhs) { return memcmp(lhs, rsh, sizeof(struct my_struct)); }然而,如果您的结构体包含指向其他结构体或联合体的指针,则需要编写一个函数来正确比较基本类型,并根据需要对其他结构体进行比较调用。
memcmp()
比较浮点数字段时,与0.0、-0.0和NaN进行比较会存在问题。二进制表示不同的指针可能指向同一位置(例如DOS:seg:offset),因此它们是相等的。某些系统具有多个空指针,这些指针比较相等。类似地,对于带有负零和冗余编码的晦涩整数以及Intel长双精度、decimal64等冗余编码的浮点类型,也存在相同的问题。这些问题无论是否使用calloc()
或填充都没有影响。 - chux - Reinstate Monica==
无法与结构体一起使用(就像我一样),请参见 https://dev59.com/babja4cB1Zd3GeqPelRC。 - stefanct