2

在 C 语言中(或者可能在一般情况下)使用算术获取值或从数组/变量中调用它是否更快?

例如,如果我有

int myarray[7] = {16};
int mysixteen = 16;

然后我可以通过多种不同的方式获得 16

myarray[#]
mysixteen
16
1 << 4
10 + 6

从逻辑上讲,16 是最快的,但对于一组数字来说,这并不总是方便或合理的。一个可能与此相关的示例是预计算表。假设您需要 64 位的位掩码,您可以填充一个数组

for (int i = 0; i < 64; ++i) {
    mask[i] = 1 << i;
}

并在将来调用数组,或者创建一个宏

#define mask(b) (1 << b)

并称之为。

4

2 回答 2

2

一般来说,任何

  • 16
  • 1 << 4
  • 10 + 6

将产生文字16,因为编译器肯定会实现称为常量折叠的优化。

的表现

  • 我的十六
  • 我的数组[n]

可能较低,具体取决于这些变量的值存储在哪里。在记忆中?如果是这样,内存是否在任何 CPU 缓存中?或者它是否存储在 CPU 寄存器之一中?没有确定的答案。

我一般来说,对于一个特定的程序,你总是可以看到你的编译器给你什么——但请注意,这可能会根据周围的代码和你的优化标志而发生很大变化。

要自己尝试,请考虑这个小程序:

int f() { return 16; }

int g() { return 1 << 4; }

int h() { return 10 + 6; }

int i() {
    int myarray[7] = { 16 };
    return myarray[3];
}

int j() {
    int mysixteen = 16;
    return mysixteen;
}

如果我使用 gcc 4.7.2 编译它然后检查反汇编,比如

$ gcc -c so19802742.c -o so19802742.o
$ objdump --disassemble so19802742.o

我明白了:

0000000000000000 <f>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   b8 10 00 00 00          mov    $0x10,%eax
   9:   5d                      pop    %rbp
   a:   c3                      retq   

000000000000000b <g>:
   b:   55                      push   %rbp
   c:   48 89 e5                mov    %rsp,%rbp
   f:   b8 10 00 00 00          mov    $0x10,%eax
  14:   5d                      pop    %rbp
  15:   c3                      retq   

0000000000000016 <h>:
  16:   55                      push   %rbp
  17:   48 89 e5                mov    %rsp,%rbp
  1a:   b8 10 00 00 00          mov    $0x10,%eax
  1f:   5d                      pop    %rbp
  20:   c3                      retq   

0000000000000021 <i>:
  21:   55                      push   %rbp
  22:   48 89 e5                mov    %rsp,%rbp
  25:   48 c7 45 e0 00 00 00    movq   $0x0,-0x20(%rbp)
  2c:   00 
  2d:   48 c7 45 e8 00 00 00    movq   $0x0,-0x18(%rbp)
  34:   00 
  35:   48 c7 45 f0 00 00 00    movq   $0x0,-0x10(%rbp)
  3c:   00 
  3d:   c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%rbp)
  44:   c7 45 e0 10 00 00 00    movl   $0x10,-0x20(%rbp)
  4b:   8b 45 ec                mov    -0x14(%rbp),%eax
  4e:   5d                      pop    %rbp
  4f:   c3                      retq   

0000000000000050 <j>:
  50:   55                      push   %rbp
  51:   48 89 e5                mov    %rsp,%rbp
  54:   c7 45 fc 10 00 00 00    movl   $0x10,-0x4(%rbp)
  5b:   8b 45 fc                mov    -0x4(%rbp),%eax
  5e:   5d                      pop    %rbp
  5f:   c3                      retq   

请注意,由于不断折叠,如何f产生完全相同的机器代码。数组访问会导致最多的机器代码(但不一定是最慢的!)并且介于两者之间。ghij

但是,这根本没有任何更复杂的代码优化!使用 eg 编译时生成的代码-O2可能完全不同,因为编译器注意到调用这五个函数中的任何一个都等同于仅使用常量16

于 2013-11-18T13:41:18.093 回答
0

你不应该担心这些事情。在大多数情况下,编译器足够聪明。甚至像乘法这样的基本操作有时也被优化为使用移位,因为这样更有效。

谈到您的示例,数组版本需要大量内存访问,这非常慢。在大多数情况下,宏会更快,具体取决于访问次数。

于 2013-11-18T13:28:29.920 回答