你如何在C中比较结构的相等性?

问题描述 投票:190回答:11

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

c struct equality
11个回答
176
投票

C没有提供语言功能 - 您必须自己完成并按成员比较每个结构成员。


-1
投票

如果2个结构变量用calloc初始化,或者它们被memset设置为0,那么你可以将你的2个结构与memcmp进行比较,不用担心结构垃圾,这样你就可以节省时间


-2
投票

此兼容示例使用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))) {
    /* ... */
  }
}

100
投票

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

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


20
投票

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

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


17
投票

由于结构中字段之间存在潜在的随机填充字符,因此无法使用memcmp来比较结构的相等性。

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

对于像这样的结构,上面的代码会失败:

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

您必须使用成员比较才能安全。


5
投票

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

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


5
投票

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

如果出现以下情况,可以使用memcmp

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

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

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

我还没有看到这样的代码生成库。但是,它看起来相对简单。

但是,这种生成的相等函数通常也会在应用程序级别执行错误操作。例如,应该在Windows中对两个UNICODE_STRING结构进行浅层或深度比较?


2
投票

这取决于你问的问题是:

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

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

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

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


2
投票

memcmp不比较结构,memcmp比较二进制,并且结构中总是有垃圾,因此它总是比较错误。

逐个元素地比较它的安全性并且不会失败。


1
投票

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

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初始化的一部分。

© www.soinside.com 2019 - 2024. All rights reserved.