【问题标题】:Can I use memcmp to check struct for non-zero members?我可以使用 memcmp 检查结构中的非零成员吗?
【发布时间】:2016-10-14 02:52:24
【问题描述】:

我正在使用一个包含许多成员的大型结构,我想要一种简单的方法来快速查看是否有任何成员非零。我知道 memcmp() 不应该用于比较两个结构的相等性(如此处所述:How do you compare structs for equality in C?),但我希望通过将结构与已设置为 0 的内存块进行比较,这可能有效.

例如,假设我有一些结构:

typedef struct {
    int Int1;
    int Int2;
    int Int3;
} MyInts;

我从这个结构创建一个变量:

MyInts MyStruct = {0};

在我的程序执行过程中,MyStruct 的成员通常为 0,但偶尔可能会临时设置为某个非零值。我想快速检查MyStruct 中的任何整数是否非零。我可以像下面这样使用memcmp()吗?

// Create empty struct to test against
MyInts EmptyStruct = {0};

// Make sure entire memory block of test struct is cleared
memset(&EmptyStruct, 0, sizeof(MyInts));

// Compare MyStruct to EmptyStruct to see if any non-zero members exist
int result = memcmp(&MyStruct, &EmptyStruct, sizeof(MyInts));

【问题讨论】:

  • 注意:double fn = -0.0; fp = 0.0; --> fn == fp,两者都等于零。然而memcmp(&fp, &fn, sizeof fp) 报告了差异。
  • 不要把MyInts EmptyStruct = {0}; 指定为将填充初始化为零位。
  • @chux 保证将填充设置为零位,请参阅 C11 6.7.9/10(和 /21 指回 /10)
  • @M.M 感谢您的引用。
  • 如果你的系统有memcchr,应该比memcmp效率更高。

标签: c struct memcmp


【解决方案1】:

在一般情况下您不能这样做,因为结构可以在字段之间和结构末尾进行填充,并且不能保证填充字节的内容(可能是未初始化的垃圾)。

如果两个被比较的结构最初分配有calloc,或者在填充实际值之前将sizeof(thestruct)字节memset设置为零,那么填充将具有可预测的值,和memcmp 会工作。同样,如果你能保证没有填充,那么这个memcmp 会起作用。但如果其中一个可能没有被归零,不,不安全。

当然,如果你想变得“好”,你可以直接比较成员,可能在一个分解出来的函数中,让编译器处理优化,而不用担心你是否有未清零的结构和填充浮动。

注意:您提供的链接中的The second highest voted answer 涵盖了这一点。该答案的 cmets 还注意到一些边缘情况,例如floats 可以具有比较相等但具有不同位表示的值,因此即使这样也不能推广到所有结构。

【讨论】:

  • 嗯。填充是否被指定为稳定的结构分配,如a = b
  • 啊,你的评论很有道理。感谢您的快速回复!
  • 结构赋值 (C11 6.2.6.1/6) 可能不会保留填充。我也不清楚是否可以通过分配给单个成员来保证保留填充。
  • 感谢您的澄清,@M.M
  • 写入填充总是 100% 合法的吗?因此,您可以“使用”结构中的所有字节,即使它们不是任何变量的一部分,并且仍然不会调用未定义的行为?
【解决方案2】:

为了清楚起见,我决定继续根据 cmets 回答我自己的问题。正如@M.M 所提到的,填充不能保证被结构赋值保留,也可能不被单个成员赋值保留。因此,使用memcmp 检查结构中的非零成员是不安全的。

ShadowRanger suggests 一样,安全的方法是单独比较每个结构成员。

【讨论】:

    猜你喜欢
    • 2020-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-12
    • 1970-01-01
    相关资源
    最近更新 更多