【问题标题】:Repetitive calculations with sizeof, strlen, etc使用 sizeof、strlen 等进行重复计算
【发布时间】:2021-01-31 06:22:35
【问题描述】:

假设我有一个大数组,我正在执行以下操作:

for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); ++i)
    printf("arr[%d]=%d\n", i, arr[i]);

当然,sizeof 的东西不应该每次都计算,所以应该是这样的:

size_t len = sizeof(arr)/sizeof(arr[0]);
for (int i = 0; i < len; ++i)
    printf("arr[%d]=%d\n", i, arr[i]);

我的问题是,是否可以假设任何编译器都会自动进行上述优化,所以我使用哪种方法并不重要?或者我应该假设情况并非如此,第二种方法是唯一正确的方法。

【问题讨论】:

  • 优化将取决于您使用的编译器。我肯定会采用第二种方法。
  • sizeofstrlen 在这里是完全不同的动物。 sizeof(type)sizeof(obj) 是一个编译时间常数,除了 VLA,所以 sizeof(arr)/sizeof(arr[0]) 只是被编译器视为 24/4constant folding 在任何理智的编译器上都会将其转换为常数 6 .但strlen 是完全不同的情况。
  • @NateEldredge 我明白了,但是在上面是的,它也可能是 VLA。
  • 即便如此,它不能在迭代之间改变,所以它应该是 hoisted 的循环。但在for (i = 0; i &lt; strlen(s); i++) 的情况下,编译器不得不怀疑循环体是否会修改字符串s。如果它不能证明它没有,这可能很难,那么它必须在每次迭代时再次调用strlen

标签: c compiler-optimization


【解决方案1】:

没有理由将除法提升到循环条件之外。它甚至不是计算除法多少次的问题(在这些情况下通常关心的是,并且可能需要编译器使用“转义分析”来确定长度值是否可以在迭代之间改变)。一个简单的事实是,sizeof(arr)/sizeof(arr[0]) 是一个常量表达式,将在编译时进行计算,与您在那里硬编码一个数字没有什么不同。

【讨论】:

  • 我明白了,这也适用于strlen(x),还是strlen 完全不同?
  • strlen(x) 非常不同。正如我所提到的,编译器可能会使用转义分析来确定该表达式的结果是否可以在每次迭代中改变(例如,如果字符串x 指向被修改)。如果优化器可以确定strlen(x) 的结果在每次迭代中都是相同的,那么它当然应该只评估一次。但这远没有sizeof 的案例那么明确和明显。
猜你喜欢
  • 1970-01-01
  • 2012-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-14
  • 1970-01-01
  • 2018-01-13
相关资源
最近更新 更多