【问题标题】:Most efficient pointer arithmetic type in cc中最有效的指针算术类型
【发布时间】:2014-02-06 07:06:51
【问题描述】:

我假设当我们写:arr[i](相当于*(arr+i))时会发生内部转换。因为i 可以是例如shortintlong 或这三个中任何一个的无符号变体。

所以我的问题很简单:i 应该是哪种类型才能不发生内部转换?这样代码才能最高效地运行?

粗略猜测:size_t?

【问题讨论】:

  • 如果您为int8_t 直到并包括ptrdiff_t(我的提名人)设置测试用例,我会更感兴趣,以查看发布级 asm 的实际外观以及差异是(或不是)。
  • FWIW,我可以确认使用“错误”的索引大小确实会导致数组访问的符号/零扩展指令。但与此同时,编译器非常擅长通过common subexpression elimination 优化它们。
  • @StackedCrooked 不是真的。在我的机器上,int 是 32 位。但我可以做 64 位索引。
  • @makhlaghi 因此编译器将首先对其进行编译以对每个数组访问进行扩展。但随后它会看到对同一个变量的扩展一次又一次地完成。所以它会做一次并重用扩展的结果。 (又名通用子表达式消除)
  • 访问数组最快的方法是根本不使用下标运算符。比如for (int i = 0; i < n; i++) f(array[i])最好写成for (array_type* p = array; p < array+n; p++) f(*p)这样,你只需要加一个地址和一个整数一次。还有一点:说到性能,不要争论,要衡量!如果您执行 user2485710 建议的操作,则可以使用例如对代码进行一次基准测试。 size_tptrdiff_t 一次,看看它是否有什么不同。只有这样,您才需要考虑使用哪个。

标签: c performance pointers pointer-arithmetic


【解决方案1】:

这不太可能对性能产生任何显着影响。在任何情况下,您都应该始终使用语义正确的类型,而不是试图对无关紧要的事物进行过早的优化。在索引的情况下,size_t先验正确的最小类型,但如果你知道你正在使用的数组是有界的,你可能能够摆脱较小的类型。通常,尽管您应该只使用 size_t 以确保安全。

【讨论】:

  • 严格来说,ptrdiff_t 用于索引,而不是size_t。这么多整数类型...
  • 谢谢,我一直在使用size_t。但如果它不是正确的类型,隐式转换会以任何方式发生,对吧?如果我们可以避免它,并且它符合代码的语义,我们为什么不呢?
  • 除了 fake-32-on-64 目标,如 MIPS n32 或 x86_64 上的“x32”,size_t 无论如何都将是本机寄存器大小,并且至少与用作索引的任何其他类型。顺便说一句,没有“隐式演员”之类的东西。根据定义,强制转换是用于执行转换的显式运算符。
  • @user2357112 ptrdiff_t 已签名,应避免使用。
  • @makhlaghi 应该避免这种情况,因为它可能会将较大的正值视为负值。
【解决方案2】:

我的回答是保持简单,也许你想typedef 一个类型为你索引像这样

typedef size_t TPtrIdx;

通过这种方式,您可以轻松地将类型转换为现在或 1 年后的任何您想要的类型。

关于从/到有符号和无符号类型的转换之间的潜在问题,这是一个好的编译器可以为您处理的问题,例如gcc 提供了-Wconversion 标志,启用它总是一件好事。

【讨论】:

  • 非常感谢您提供的非常有趣的建议。我会一直这样做,直到找到一个好的答案。
猜你喜欢
  • 2010-10-20
  • 1970-01-01
  • 2017-05-29
  • 2012-07-27
  • 1970-01-01
  • 1970-01-01
  • 2017-09-19
相关资源
最近更新 更多