C ++:是否优化了if()指针检查?

时间:2013-07-10 03:02:33

标签: c++ loops compiler-optimization

以下代码测试2个setter呼叫的时钟时间。一个检查空指针,一个不检查。编译的程序输出-O3标志给出相同的时间:

  0.000000 ticks (0.000000 secs)
  0.000000 ticks (0.000000 secs)
带有-O0标志的

,时序差异仍然很小

  4250000.0000 ticks (4.25000 secs)
  4230000.0000 ticks (4.25000 secs)

这是由编译器在for循环中优化的吗?如果是这样,那么如何测试两个效率差异的“真实”世界情景呢?

class B {};
class A
{
public:
      void set( int a ) { a_ = a; }
      int get() const { return a_; }
private:
      int a_;
};

class A1

public:
      A1() : b_(0) {}

      void set( int a ) { if( b_ ) a_ = a; }
      int get() const { return a_; }

private:
      int a_;
      B* b_;
}; 


int main()
{
      const int n=1000000000;
      clock_t t0, t1;

      A a;
      A1 a1;

      t0 = clock();
      for( int i=0; i < n; ++i ) 
            a.set( i );
      t1 = clock();
      printf( "%f ticks (%.6f secs)\n", (double) t1-t0, ((double) t1-t0) / CLOCKS_PER_SEC );

      t0 = clock();
      for( int i=0; i < n; ++i ) 
            a1.set( i );
      t1 = clock();
      printf( "%f ticks (%.6f secs)\n", (double) t1-t0, ((double) t1-t0) / CLOCKS_PER_SEC );

      return 0;
}

2 个答案:

答案 0 :(得分:4)

检查空指针几乎肯定是一个时钟周期操作。在任何现代处理器上,这将是一个二十亿分之一秒。我认为这超出了滴答计数器的分辨率(根据平台确定毫秒或微秒)。

如果您真的想知道,请查看调试器中发出的汇编代码。

答案 1 :(得分:0)

-O3情况下的测量结果为0,因此编译器的优化程度远远超过空指针检查。它完全删除了循环,原因是循环中生成的结果从未使用过。

代码中确实有a.get();a1.get();来检索循环中生成的值,但同样,这些函数调用的结果不会涉及任何副作用,因此编译器删除它们。

如果您使用get()调用之后放置的打印语句替换这些clock()次调用(以确保时间测量中不包含IO),则会有所不同结果(我已从输出中删除了aa1的实际值):

2540000.000000 ticks (2.540000 secs)
0.000000 ticks (0.000000 secs)

所以第一个循环现在执行一些实际操作,而第二个循环仍然被优化(Clang 3.3)。原因可能是a1._a的设置取决于初始化为0然后在循环中从未改变的指针。在将函数调用a1.set()内联到主循环之后,编译器很容易看到a1._a的赋值永远不会发生。


(注意:由于a1._a从未实际设置,因此打印其值意味着打印一个从未初始化的变量的值。事实上,我得到一个非常随机的输出,当然,严格来说,打印该值会调用未定义的行为。)