作者:围脖上的博博_771 | 2023-09-04 18:50
如何比较标准C中两个结构的实例是否相等?
1> Greg Hewgill..:
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在我所知道的*任何*现代32或64位系统上,唯一的问题是浮点数。
如果你想知道为什么`==`不使用结构(比如我),请参阅/sf/ask/17360801/ -C
@Demi:今天。对C程序员的第十条诫命是:“你应该放弃,放弃和废除宣称“全世界都是VAX”……的邪恶异端……”。用“全世界的PC”代替它并没有改善。
@MartinBonner您能命名一个仍在使用的特定系统吗,如果该结构既没有填充(也没有使用-Wpapped`来检查)或浮点值,则无法在该系统上使用`memcmp`?
2> Sufian..:
您可能很想使用memcmp(&a, &b, sizeof(struct foo))
它,但它可能无法在所有情况下使用.编译器可以将对齐缓冲区空间添加到结构,并且在位于缓冲区空间中的存储器位置处找到的值不保证是任何特定值.
但是,如果在使用它们之前使用calloc
或者使用memset
结构的完整大小,则可以进行浅层比较memcmp
(如果结构包含指针,则仅当指针指向的地址相同时才匹配).
关闭,因为它适用于"几乎所有"编译器,但并不完全.在C90中查看6.2.1.6.4:"具有相同对象表示的两个值(除NaN之外)比较相等,但比较相等的值可能具有不同的对象表示."
考虑一个"BOOL"字段.在相等性方面,任何非零BOOL都等于每个非零BOOL值.因此,虽然1和2可能都为TRUE因此相等,但memcmp将失败.
@JSalazar也许对你来说更容易,但对于编译器和CPU来说要困难得多,因此也要慢得多.为什么你认为编译器首先添加填充?当然不要浪费记忆;)
@Demetri:但很多都包含浮点数,提问者问"你如何比较结构",而不是"如何比较不包含浮点数的结构".这个答案说,如果首先清除内存,你可以与`memcmp'进行浅层比较.哪个接近工作但不正确.问题也没有定义"相等",所以如果你把它的意思是"对象表示的字节相等",那么`memcmp'就是这样做的(无论内存是否被清除).
@Demetri:例如浮点值正和负零在任何IEEE浮点实现上比较相等,但它们没有相同的对象表示.所以实际上我不应该说它适用于"几乎所有的编译器",它会在任何允许你存储负零的实现上失败.在我发表评论时,我可能正在考虑有趣的整数表示.
什么?任何人都可以解释史蒂夫的报价吗?
谢谢ajs.这是史蒂夫所做的一个好点.
3> Ben..:
如果你做了很多我建议写一个比较两个结构的函数.这样,如果你改变了结构,你只需要在一个地方改变比较.
至于怎么做....你需要单独比较每个元素
4> 小智..:
由于结构中字段之间存在潜在的随机填充字符,因此无法使用memcmp来比较结构的相等性.
// bad
memcmp(&struct1, &struct2, sizeof(struct1));
对于像这样的结构,上面会失败:
typedef struct Foo {
char a;
/* padding */
double d;
/* padding */
char e;
/* padding */
int f;
} Foo ;
您必须使用成员比较才能安全.
不太可能在双重后填充; 在双倍之后,char将立即完全对齐.
5> Demi..:
@Greg是正确的,在一般情况下必须编写显式比较函数.
可以使用memcmp
if:
结构体不包含可能的浮点字段NaN
.
结构体不包含填充(-Wpadded
与clang一起使用来检查)或者memset
在初始化时显式初始化结构.
没有成员类型(例如Windows BOOL
)具有不同但等效的值.
除非您正在为嵌入式系统编程(或编写可能在其上使用的库),否则我不会担心C标准中的一些极端情况.在任何32位或64位设备上都不存在近与远指针的区别.我所知道的非嵌入式系统没有多个NULL
指针.
另一种选择是自动生成相等函数.如果以简单的方式放置结构定义,则可以使用简单的文本处理来处理简单的结构定义.您可以将libclang用于一般情况 - 因为它使用与Clang相同的前端,它可以正确处理所有角落情况(禁止错误).
我还没有看到这样的代码生成库.但是,它看起来相对简单.
但是,这种生成的相等函数通常也会在应用程序级别执行错误操作.例如,UNICODE_STRING
Windows中的两个结构应该浅或深吗?
在进一步写入struct元素后,使用`memset`等显式初始化结构并不能保证填充位的值,请参见:/sf/ask/17360801/