Answers:
C没有提供语言工具来执行此操作-您必须自己做,并逐个成员比较每个结构。
0.0, -0.0 NaN
是的问题memcmp()
。二进制表示形式不同的指针可能指向相同的位置(例如DOS:seg:offset),因此相等。一些系统具有多个相等比较的空指针。对于int
-0 晦涩难懂和带有冗余编码的浮点类型也是如此。(Intel long double,decimal64等),这些问题使calloc()
使用与否或填充没有区别。
==
不能像我这样使用结构,请访问stackoverflow.com/questions/46995631/…–
您可能会想使用 memcmp(&a, &b, sizeof(struct foo))
,但不一定在所有情况下都可以。编译器可能会向结构中添加对齐缓冲区空间,并且不能保证在缓冲区空间中位于内存位置的值是任何特定值。
但是,如果在使用结构之前使用它们calloc
或使用memset
结构的完整大小,则可以与之进行浅层比较memcmp
(如果结构包含指针,则仅当指针指向的地址相同时,它才会匹配)。
memcmp
先清除内存,则可以进行比较。这接近工作,但不正确。Ofc这个问题也没有定义“相等性”,因此,如果您将其表示为“对象表示形式的字节相等性”,那么memcmp
它确实可以做到这一点(无论是否清除了内存)。
由于结构中字段之间可能存在随机填充字符,因此无法使用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
与clang一起使用以检查此内容),或者结构体使用显式初始化memset
。BOOL
)具有不同但等效的值。除非您正在为嵌入式系统编程(或编写可能在其上使用的库),否则我不会担心C标准中的一些特殊情况。在任何32位或64位设备上都不存在近与远指针区别。据我所知,没有任何一个非嵌入式系统具有多个NULL
指针。
另一种选择是自动生成相等函数。如果以简单的方式布置结构定义,则可以使用简单的文本处理来处理简单的结构定义。您可以将libclang用于一般情况–因为它使用的前端与Clang相同,所以它可以正确处理所有极端情况(排除错误)。
我还没有看到这样的代码生成库。但是,它看起来相对简单。
但是,在这种情况下,此类生成的相等函数通常在应用程序级别执行错误的操作。例如,应该UNICODE_STRING
浅浅或深浅地比较Windows中的两个结构?
memset
在进一步写入struct元素后,使用等明确初始化结构不能保证填充位的值,请参阅:stackoverflow.com/q/52684192/689161
请注意,只要不初始化所有成员,就可以在非静态结构上使用memcmp(),而不必担心填充。这由C90定义:
{0, }
是否也将所有填充字节归零吗?
如果结构仅包含基元,或者您对严格相等感兴趣,则可以执行以下操作:
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)将结构的内存范围归零。
此兼容示例使用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))) {
/* ... */
}
}