比较结构体和零的首选方式

10

今天我遇到了这样一个情况:我需要判断由约40个元素组成的整个结构是否为零,也就是说每个元素都为零。
在考虑如何让它尽可能快速和高效时,我想到了三种不同的方式:

  1. 将每个元素与零进行比较,这样会产生40个if语句。
  2. 分配一个已经全为零的类似结构,并使用memcmp函数将其与该结构进行比较。
  3. 使用一个足够大的类型将该结构包装在联合体中。

例如:

typedef union {
  struct {
    uint8_t a;
    uint8_t b;
    }
  uint16_t c;
 } STRUCTURE_A;

然后将其与零进行比较。

我想知道您对这些解决方案的看法,哪一个是最快和最有效的。
如果您有更好的方法,请告诉我...
谢谢。


在if语句中检查整个结构体是否有问题,就像你可能会为零标志一样检查,这有什么问题吗? - Platinum Azure
1
你实现了你的三种不同方法并比较了它们的性能吗?你发现了什么? - Greg Hewgill
除了比较每个字段以外,我看不到其他可移植的方法来做到这一点,因为可能存在填充。 - Bwmat
@Platinum - 填充位、未初始化的成员(可能不需要所有有效数据配置)、在概念上“false”时可能为非零的成员,以及随着应用程序扩展而在将来某个时刻发生变化的任何上述情况。 - Chris Lutz
1
它是否尽可能高效并不重要吗? - sth
3个回答

17

将结构体的每个成员与0进行比较。

这是比较两个结构体对象的唯一安全方法(即使其中一个结构体对象的所有成员都设置为值0)。不要使用memcmp来比较结构体,因为结构体中填充字节的值是未指定的。请注意,不允许使用运算符==来比较结构体对象操作数。

请参阅c-faq链接了解有关结构体对象比较的信息:

Q: 是否有自动比较结构体的方法?


2
如果您已确保结构体不包含填充字节,则memcmp是安全的。尽管实现技术上允许添加任意无意义的填充字节,但在现实世界中,填充字节仅用于对齐,因此一个正确构造、自然对齐的结构体除了可能在末尾处有填充字节外,将没有其他填充字节。特别地,使用 intX_t 并在没有对齐间隙的情况下排序它们是避免任何填充的好方法。 - R.. GitHub STOP HELPING ICE
如果结构体不包含填充,并且 memcmp 确实更快,优化器肯定会看到并相应地转换您的比较。 - Bo Persson

1
如果您的结构大小小于或等于处理器的字长,您可以使用联合技巧,但是任何好的编译器都应该自动执行此操作,即它会压缩if,从而实现清晰度和性能的平衡。

0
为了代码的清晰度,正如其他人指出的那样,检查每个成员以避免填充引起的问题是最好的选择。
为了速度,可以从像这样的代码开始,只需检查每个字节是否为零。
int iszero(void * ptr, int bytes )
{
   char * bptr = (char*)ptr;
   while( bytes-- )
     if( *bptr++ )
         return 0;
  return 1;
}

然后优化以进行字对齐的比较。请查看newlib的实现,如strlen()memcpy()等示例,了解其实现方式。


这相当于 memcmp,可能会有填充问题。 - R.. GitHub STOP HELPING ICE
“等效”是指具有相同的行为(和填充问题),但我邀请您比较性能。您的代码(逐字节)非常慢,即使进行多次读取,memcmp也应该获胜。一个好的memcmp一次可以比较4、8甚至16个字节。顺便说一下,“packed”不是解决对齐问题的方法。我的评论是ouah答案的正确方式。 - R.. GitHub STOP HELPING ICE
@R..,我猜你忽略了有关优化执行字对齐比较(例如memcmp)的评论。我将其留给OP作为练习,并提供newlib作为参考实现。虽然是的,您应该注意在结构体中排序字段以减少填充的需要,但这并不总是会消除填充,而是将其移动到末尾。然后,当您有嵌套结构时,您的理论就不再适用,因为您突然又在中间出现了填充。 - Brian McFarland
@R..,我应该补充说明,我非常清楚没有任何结构体打包技术是完全可移植的,但我在野外遇到的每个C编译器都有一些技术来打包你的结构体。我也知道紧密打包你的结构体可能会影响访问非对齐整数等方面的性能。 - Brian McFarland
它的问题不仅仅是性能。例如,如果int x;struct foo bar;的成员,并且x未对齐,则&bar.x不是有效的int *。将&bar.x传递给期望int *的函数将导致未对齐的读/写和SIGBUS或更糟的情况。紧凑的结构体根本不应该被使用。就这样。 - R.. GitHub STOP HELPING ICE
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接