title: Why is memcpy slower than a reinterpret_cast when parsing binary data?
body: <h3>TLDR: I forgot to enable compiler optimizations. With the optimizations enabled the performance is (nearly) identical.</h3>
  
  <p><br/></p>
  
  <h3>Original post</h3>
  
  <p>When reading integer from binary data I noticed that memcpy is slower than a casting solution.</p>
  
  <p>Version 1: reinterpret_cast, smelly due to potential alignment problems, but also faster (?)</p>
  
  <pre><code>int get_int_v1(const char * data) { return *reinterpret_cast&lt;const int*&gt;(data); }
  </code></pre>
  
  <p>Version 2: memcpy, correct and a little slower:</p>
  
  <pre><code>int get_int_v2(const char * data) { int result; memcpy(&amp;result, data, sizeof(result)); return result; }
  </code></pre>
  
  <p>I have <a href="http://ideone.com/6LEmA3" rel="noreferrer">a benchmark on Ideone</a>.</p>
  
  <p>For future reference, the code is:</p>
  
  <pre><code>#include &lt;cstdlib&gt;
  #include &lt;cstdio&gt;
  #include &lt;cstring&gt;
  #include &lt;ctime&gt;
  #include &lt;iostream&gt;
  #include &lt;vector&gt;
  #include &lt;sys/time.h&gt;
  
  double get_current_time()
  {
      timeval tv;
      gettimeofday(&amp;tv, NULL);
      return double (tv.tv_sec) + 0.000001 * tv.tv_usec;
  }
  
  int get_int_v1(const char * data) { return *reinterpret_cast&lt;const int*&gt;(data); }
  int get_int_v2(const char * data) { int result; memcpy(&amp;result, data, sizeof(result)); return result; }
  
  const unsigned iterations = 200 * 1000 * 1000;
  
  double test_v1(const char * c, unsigned &amp; prevent_optimization)
  {
      double start = get_current_time();
      for (unsigned i = 0; i != iterations; ++i)
      {
          prevent_optimization += get_int_v1(c);
      }
      return get_current_time() - start;
  }
  
  double test_v2(const char * c, unsigned &amp; prevent_optimization)
  {
      double start = get_current_time();
      for (unsigned i = 0; i != iterations; ++i)
      {
          prevent_optimization += get_int_v2(c);
      }
      return get_current_time() - start;
  }
  
  int main()
  {
      srand(time(0));
  
      // Initialize data
      std::vector&lt;int&gt; numbers(1000);
      for (std::vector&lt;int&gt;::size_type i = 0; i != numbers.size(); ++i)
      {
          numbers[i] = i;
      }
  
      // Repeat benchmark 4 times.
      for (unsigned i = 0; i != 4; ++i)
      {
          unsigned p = 0;
          std::vector&lt;int&gt;::size_type index = rand() % numbers.size();
          const char * c = reinterpret_cast&lt;const char *&gt;(&amp;numbers[index]);    
          std::cout &lt;&lt; "v1: " &lt;&lt; test_v1(c, p) &lt;&lt; std::endl;
          std::cout &lt;&lt; "v2: " &lt;&lt; test_v2(c, p) &lt;&lt; std::endl &lt;&lt; std::endl;
      }
  }
  </code></pre>
  
  <p>And the results are:</p>
  
  <pre><code>v1: 0.176457
  v2: 0.557588
  
  v1: 0.17654
  v2: 0.220581
  
  v1: 0.176826
  v2: 0.22012
  
  v1: 0.176131
  v2: 0.220633
  </code></pre>
  
  <p>My questions are: </p>
  
  <ul>
  <li>Is my benchmark correct?</li>
  <li>If yes, then why is v2 (with memcpy) slower? Since both version return a copy of the data I think there should be no difference in performance.</li>
  <li>How can I implement a solution that is correct and fast?</li>
  </ul>
  
  <p><br/></p>
  
  <h3>Update</h3>
  
  <p>I was being silly and forgot to consider that Ideone doesn't perform compiler optimizations. I also tweaked the code a little and came up with the following:</p>
  
  <pre><code>#include &lt;algorithm&gt;
  #include &lt;cstdlib&gt;
  #include &lt;cstdio&gt;
  #include &lt;cstring&gt;
  #include &lt;ctime&gt;
  #include &lt;iomanip&gt; 
  #include &lt;iostream&gt; 
  #include &lt;vector&gt;
  #include &lt;sys/time.h&gt;
  
  double get_current_time()
  {
      timeval tv;
      gettimeofday(&amp;tv, NULL);
      return double (tv.tv_sec) + 0.000001 * tv.tv_usec;
  }
  
  struct test_cast
  {
      int operator()(const char * data) const 
      {
          return *((int*)data);
      }
  };
  
  struct test_memcpy
  {
      int operator()(const char * data) const 
      {
          int result;
          memcpy(&amp;result, data, sizeof(result));
          return result;
      }
  };
  
  struct test_std_copy
  {
      int operator()(const char * data) const 
      {
          int result;
          std::copy(data, data + sizeof(int), reinterpret_cast&lt;char *&gt;(&amp;result));
          return result;
      }
  };
  
  enum
  {
      iterations = 2000,
      container_size = 2000
  };
  
  std::vector&lt;int&gt; get_random_numbers()
  {
      std::vector&lt;int&gt; numbers(container_size);
      for (std::vector&lt;int&gt;::size_type i = 0; i != numbers.size(); ++i)
      {
          numbers[i] = rand();
      }
      return numbers;
  }
  
  std::vector&lt;int&gt; get_random_indices()
  {
      std::vector&lt;int&gt; numbers(container_size);
      for (std::vector&lt;int&gt;::size_type i = 0; i != numbers.size(); ++i)
      {
          numbers[i] = i;
      }
      std::random_shuffle(numbers.begin(), numbers.end());
      return numbers;
  }
  
  template&lt;typename Function&gt;
  unsigned benchmark(const Function &amp; f, unsigned &amp; counter)
  {
      std::vector&lt;int&gt; container = get_random_numbers();
      std::vector&lt;int&gt; indices = get_random_indices();
      double start = get_current_time();
      for (unsigned iter = 0; iter != iterations; ++iter)
      {
          for (unsigned i = 0; i != container.size(); ++i)
          {
              counter += f(reinterpret_cast&lt;const char*&gt;(&amp;container[indices[i]]));
          }
      }
      return unsigned(0.5 + 1000.0 * (get_current_time() - start));
  }
  
  int main()
  {
      srand(time(0));
      unsigned counter = 0;
  
      std::cout &lt;&lt; "cast:      " &lt;&lt; benchmark(test_cast(),     counter) &lt;&lt; " ms" &lt;&lt; std::endl;
      std::cout &lt;&lt; "memcpy:    " &lt;&lt; benchmark(test_memcpy(),   counter) &lt;&lt; " ms" &lt;&lt; std::endl;
      std::cout &lt;&lt; "std::copy: " &lt;&lt; benchmark(test_std_copy(), counter) &lt;&lt; " ms" &lt;&lt; std::endl;
      std::cout &lt;&lt; "(counter:  " &lt;&lt; counter &lt;&lt; ")" &lt;&lt; std::endl &lt;&lt; std::endl;
  
  }
  </code></pre>
  
  <p>The results are now nearly equal (except for <code>std::copy</code> which is slower for some reason):</p>
  
  <pre><code>g++ -o test -O0 -Wall -Werror -Wextra -pedantic-errors main.cpp
  cast:      56 ms
  memcpy:    60 ms
  std::copy: 290 ms
  (counter:  2854155632)
  
  g++ -o test -O1 -Wall -Werror -Wextra -pedantic-errors main.cpp
  cast:      9 ms
  memcpy:    14 ms
  std::copy: 20 ms
  (counter:  3524665968)
  
  g++ -o test -O2 -Wall -Werror -Wextra -pedantic-errors main.cpp
  cast:      4 ms
  memcpy:    5 ms
  std::copy: 20 ms
  (counter:  2590914608)
  
  g++ -o test -O3 -Wall -Werror -Wextra -pedantic-errors main.cpp
  cast:      4 ms
  memcpy:    5 ms
  std::copy: 18 ms
  (counter:  2590914608)
  </code></pre>