您如何比较 C 中的结构是不是相等?

Posted

技术标签:

【中文标题】您如何比较 C 中的结构是不是相等?【英文标题】:How do you compare structs for equality in C?您如何比较 C 中的结构是否相等? 【发布时间】:2010-09-13 14:13:00 【问题描述】:

如何比较标准 C 中结构的两个实例是否相等?

【问题讨论】:

【参考方案1】:

C 没有提供任何语言工具来执行此操作 - 您必须自己完成并逐个比较每个结构成员。

【讨论】:

如果 2 个结构变量是用 calloc 初始化的,或者它们被 memset 设置为 0,那么你可以将你的 2 个结构与 memcmp 进行比较,并且不用担心结构垃圾,这会让你赢得时间 @MOHAMED 将浮点字段与0.0, -0.0 NaN 进行比较是memcmp() 的问题。二进制表示不同的指针可能指向相同的位置(例如 DOS: seg:offset),因此是相等的。一些系统有多个相等比较的空指针。对于带有 -0 和带有冗余编码的浮点类型的模糊 int 也是如此。 (Intel long double、decimal64等)这些问题没有区别是calloc()使用与否或填充。 @chux 在我所知道的 any 现代 32 位或 64 位系统上,唯一的问题是浮点数。 如果您想知道为什么 == 不能使用结构(如我),请参阅 ***.com/questions/46995631/… @Demi:今天。 C 程序员的第 10 条诫命是“你应该放弃、放弃和放弃声称“全世界都是 VAX”的邪恶异端邪说……”。用“All the world's a PC”代替它并不是一种改进。【参考方案2】:

您可能很想使用memcmp(&a, &b, sizeof(struct foo)),但它可能不适用于所有情况。编译器可能会将对齐缓冲区空间添加到结构中,并且不保证在缓冲区空间中的内存位置找到的值是任何特定值。

但是,如果您在使用 callocmemset 之前使用结构的完整大小,您可以memcmp进行比较(如果您的结构包含指针,则仅当指针指向的地址相同时才会匹配。

【讨论】:

关闭,因为它适用于“几乎所有”编译器,但不完全适用。查看 C90 中的 6.2.1.6.4:“具有相同对象表示的两个值(NaN 除外)比较相等,但比较相等的值可能具有不同的对象表示。” 考虑一个“BOOL”字段。就相等而言,任何非零 BOOL 都等于每个非零 BOOL 值。因此,虽然 1 和 2 可能都为 TRUE 并因此相等,但 memcmp 将失败。 @JSalazar 也许对你来说更容易,但对编译器和 CPU 来说更难,因此也慢得多。为什么你认为编译器首先添加填充?当然不要白白浪费内存;) @Demetri:例如,浮点值正零和负零在任何 IEEE 浮点实现上比较相等,但它们没有相同的对象表示。所以实际上我不应该说它适用于“几乎所有编译器”,它会在任何让你存储负零的实现上失败。我发表评论时可能正在考虑有趣的整数表示。 @Demetri:但许多确实包含浮点数,提问者问“你如何比较结构”,而不是“你如何比较不包含浮点数的结构”。这个答案说您可以与memcmp 进行浅比较,前提是先清除内存。这接近工作但不正确。 Ofc 这个问题也没有定义“平等”,所以如果你把它理解为“对象表示的字节平等”,那么memcmp 就是这样做的(无论内存是否被清除)。【参考方案3】:

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

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

【讨论】:

即使只使用一次,我也会编写一个单独的函数。【参考方案4】:

由于结构中的字段之间可能存在随机填充字符,因此您不能使用 memcmp 来比较结构是否相等。

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

对于这样的结构,上述操作会失败:

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

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

【讨论】:

不太可能在双精度后填充; char 将在 double 之后立即完全充分对齐。【参考方案5】:

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

可以使用memcmp 如果:

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

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

另一个选项是自动生成相等函数。如果您以简单的方式布置结构定义,则可以使用简单的文本处理来处理简单的结构定义。您可以将 libclang 用于一般情况 - 因为它使用与 Clang 相同的前端,所以它可以正确处理所有极端情况(排除错误)。

我还没有见过这样的代码生成库。不过看起来比较简单。

但是,这种生成的相等函数也经常会在应用程序级别做错事。例如,Windows 中的两个UNICODE_STRING struct 应该浅比较还是深比较?

【讨论】:

memset等显式初始化结构体并不能保证进一步写入结构体元素后填充位的值,见:***.com/q/52684192/689161【参考方案6】:

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

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

【讨论】:

是否真的指定0, 也会将任何填充字节归零? GCC 至少将部分初始化结构的填充字节归零,如上面的链接所示,***.com/questions/13056364/… 详细说明了 C11 指定的行为。 一般来说不是很有用,因为所有填充在分配给任何成员时都会变得不确定【参考方案7】:

这取决于你问的问题是否是:

    这两个结构是同一个对象吗? 它们的值是否相同?

要确定它们是否是同一个对象,请比较指向这两个结构的指针是否相等。 如果您想大致了解它们是否具有相同的值,则必须进行深入比较。这涉及比较所有成员。如果成员是指向其他结构的指针,您也需要递归到这些结构中。

在结构不包含指针的特殊情况下,您可以使用 memcmp 对每个结构中包含的数据执行按位比较,而无需知道数据的含义。

确保您知道“等于”对每个成员的含义 - 对于整数来说很明显,但对于浮点值或用户定义的类型来说更微妙。

【讨论】:

【参考方案8】:

memcmp不比较结构,memcmp比较二进制,结构中总是有垃圾,所以比较总是假。

逐个元素比较其安全且不会失败。

【讨论】:

如果 2 个结构变量是用 calloc 初始化的,或者它们被 memset 设置为 0,那么你可以将你的 2 个结构与 memcmp 进行比较,并且不用担心结构垃圾,这会让你赢得时间 calloc 或 memset 对你没有帮助,因为每个赋值都会返回填充字节来确定值 不,并不总是有垃圾。仅在需要时才进行填充。使用 memcmp 可以安全地比较某些结构。【参考方案9】:

如果结构只包含原语,或者如果您对严格相等感兴趣,那么您可以执行以下操作:

int my_struct_cmp(const struct my_struct * lhs, const struct my_struct * rhs) 返回 memcmp(lhs, rsh, sizeof(struct my_struct));

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

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

【讨论】:

【参考方案10】:

如果 2 个结构变量是用 calloc 初始化的,或者它们被 memset 设置为 0,那么您可以将您的 2 个结构与 memcmp 进行比较,并且不用担心结构垃圾,这将让您赢得时间

【讨论】:

【参考方案11】:

此兼容示例使用 Microsoft Visual Studio 中的#pragma pack 编译器扩展来确保结构成员尽可能紧密地打包:

#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))) 
    /* ... */
  

【讨论】:

确实是这样。但在大多数情况下,你不希望你的结构被打包!相当多的指令和指针要求输入数据是字对齐的。如果不是,那么编译器需要添加额外的指令来复制和重新对齐数据,然后才能执行实际指令。如果编译器不重新对齐数据,CPU 将抛出异常。

以上是关于您如何比较 C 中的结构是不是相等?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查数组中的所有值是不是彼此相等。 C++

C语言如何比较两个【字符】或者【字符串】是不是相等?迷糊了,求解答

C ++如何检查数组中的元素是不是相等?

linux下c如何比较两个字符串内容是不是相等

如何检查数组中的数字是不是相等?

c# 比较两个对象的值是不是相等