为什么C不提供结构比较?
正如大多数C程序员所知,你无法直接比较两种结构。
考虑:
void isequal(MY_STRUCT a, MY_STRUCT b) { if (a == b) { puts("equal"); } else { puts("not equal"); } }
a==b
比较将AFAIK在任何合理的C编译器上抛出编译错误,因为C标准不允许内置结构比较。 使用memcmp的解决方法当然是一个坏主意,因为对齐,打包,位域等,所以我们最终逐个元素比较函数。
另一方面,它允许结构分配,例如a = b
完全合法。 很明显,编译器可以相当简单地处理这个问题,为什么不进行比较呢?
我唯一的想法是结构分配可能与memcpy()非常接近,因为对齐等间隙并不重要。 另一方面,比较可能更复杂。 或者这是我缺少的东西?
显然,我知道通过元素比较做一个简单的元素不一定足够,例如,如果结构包含指向字符串的指针,但在某些情况下它会有用。
正如其他人所提到的,这里是Harbison和Steele的C:A参考手册的摘录:
即使允许对这些类型进行赋值,也无法比较结构和联合的相等性。 由对齐限制引起的结构和联合中的间隙可能包含任意值,并且对此进行补偿会对相等比较或修改结构和联合类型的所有操作施加不可接受的开销。
由于memcmp
失败的原因,不支持比较。
由于填充字段,比较将以不可预测的方式失败,这对于大多数程序员来说是不可接受的。 赋值会更改不可见的填充字段,但这些字段无论如何都是不可见的,因此没有任何意外。
显然,您可能会问:那么为什么不填充所有填充字段呢? 当然会有效,但它也会使所有程序为他们可能不需要的东西付费。
编辑
Oli Charlesworth在评论中指出,您可能会问:“为什么编译器不会为逐个成员的比较生成代码”。 如果是这样的话,我必须承认: 我不知道 :-)。 如果只允许比较完整类型,编译器将拥有所有需要的信息。
自动生成比较运算符是个坏主意。 想象一下比较如何对这个结构起作用:
struct s1 { int len; char str[100]; };
这是像字符串一样的pascal,最大长度为100
另一个案例
struct s2 { char a[100]; }
编译器如何知道如何比较字段? 如果这是一个以NUL结尾的字符串,则编译器必须使用strcmp或strncmp。 如果这是char数组编译器必须使用memcmp。
我在C理由( C99理论基础V5.10 ),6.5.9中找到了这个:
C89委员会不止一次考虑允许比较结构的平等。 这些建议在结构上的漏洞问题上失败了。 两个结构的逐字节比较将要求确保将孔设置为零,以便所有孔都相等,这对于自动或动态分配的变量来说是一项艰巨的任务。
结构中联合类型元素的可能性使这种方法产生了不可克服的问题。 如果不确保所有漏洞都设置为零,则必须准备实施以将结构比较分解为任意数量的成员比较; 因此,一个看似简单的表达式可能会扩展为大量的代码,这与C的精神背道而驰
用简单的英语:由于结构/联合可能包含填充字节,并且委员会没有强制执行这些以保存某些值,因此它们不会实现此function。 因为如果所有填充字节必须设置为零,则需要额外的运行时开销。
要添加现有的好答案:
struct foo { union { uint32_t i; float f; } u; } a, b; auf = -0.0; buf = 0.0; if (a==b) // what to do?!
问题源于工会无法存储/跟踪哪个成员是最新的。