在C语言中如何比较结构是否相等?

如何比较标准C中两个相等的struct实例?

240153 次浏览

C语言没有提供这样做的语言工具——你必须自己做,并逐个比较每个结构成员。

如果你经常这样做,我建议你写一个函数来比较这两种结构。这样,如果你改变了结构,你只需要改变一个地方的比较。

至于怎么做....您需要单独比较每个元素

你可能会被诱惑使用memcmp(&a, &b, sizeof(struct foo)),但它可能不是在所有情况下都有效。编译器可以向结构体添加对齐缓冲空间,并且在位于缓冲空间的内存位置上找到的值不保证是任何特定的值。

但是,如果在使用结构体之前使用它们的完整大小callocmemset,则可以将与memcmp进行比较(如果结构体包含指针,则只有在指针指向的地址相同时才匹配)。

你不能使用memcmp来比较结构是否相等,因为在结构的字段之间存在潜在的随机填充字符。

  // bad
memcmp(&struct1, &struct2, sizeof(struct1));

对于这样的结构体,上述方法将失败:

typedef struct Foo {
char a;
/* padding */
double d;
/* padding */
char e;
/* padding */
int f;
} Foo ;

为了安全起见,您必须使用成员比较。

如果结构只包含原语,或者如果你对严格的相等感兴趣,那么你可以这样做:

int my_struct_cmp(const struct my_struct * lhs, const struct my_struct * rhs)
{
return memcmp(lhs, rsh, sizeof(struct my_struct));
}

然而,如果你的结构体包含指向其他结构体或联合的指针,那么你就需要编写一个函数来正确地比较原语,并根据需要对其他结构进行比较调用。

但是请注意,您应该使用memset(&a, sizeof(struct my_struct), 1)来将结构体的内存范围归零,作为ADT初始化的一部分。

注意,你可以在非静态结构上使用memcmp() 担心填充,只要你没有初始化 所有成员(同时)。这由C90定义:

http://www.pixelbeat.org/programming/gcc/auto_init.html

这取决于你问的问题是:

  1. 这两个结构体是同一个对象吗?
  2. 它们的价值相同吗?

要找出它们是否是同一个对象,比较指向这两个结构体的指针是否相等。 如果你想从总体上找出它们是否具有相同的值,你必须进行深入的比较。这涉及比较所有成员。如果成员是指向其他结构的指针,你也需要递归到这些结构中

在结构不包含指针的特殊情况下,您可以执行memcmp来逐个比较每个结构中包含的数据,而不必知道这些数据的含义。

确保你知道' = '对于每个成员意味着什么——这对于整型来说很明显,但对于浮点值或用户定义的类型来说就更微妙了。

memcmp不比较结构,memcmp比较二进制,并且结构中总是有垃圾,因此在比较中总是输出False。

逐个元素比较它是安全的,不会失败。

如果这2个结构变量是用calloc初始化的,或者它们被memset设置为0,这样你就可以用memcmp比较你的2个结构,不用担心结构垃圾,这将让你赚到时间

这个兼容的例子使用了来自Microsoft Visual Studio的#pragma包编译器扩展,以确保结构成员尽可能紧密地打包:

#include <string.h>


#pragma pack(push, 1)
struct s {
char c;
int i;
char buffer[13];
};
#pragma pack(pop)


void compare(const struct s *left, const struct s *right) {
if (0 == memcmp(left, right, sizeof(struct s))) {
/* ... */
}
}

@Greg是正确的,在一般情况下必须编写显式比较函数。

在以下情况下可以使用memcmp:

  • 结构体不包含可能为NaN的浮点字段。
  • 结构体不包含填充(使用-Wpadded with clang来检查这一点)或者结构体在初始化时显式地使用memset初始化。
  • 没有成员类型(例如Windows BOOL)具有不同但等效的值。

除非你正在为嵌入式系统编程(或者编写一个可能用于嵌入式系统的库),否则我不会担心C标准中的一些极端情况。近指针和远指针的区别在任何32位或64位设备上都不存在。我所知道的非嵌入式系统中没有多个NULL指针。

另一种选择是自动生成相等函数。如果以简单的方式布局结构定义,则可以使用简单的文本处理来处理简单的结构定义。对于一般情况,可以使用libclang;由于它使用与Clang相同的前端,它可以正确地处理所有角落的情况(排除bug)。

我还没有见过这样的代码生成库。然而,它看起来相对简单。

然而,这种生成的相等函数在应用程序级别上经常会做错误的事情。例如,Windows中的两个UNICODE_STRING结构体应该进行浅比较还是深比较?