memcmp / strcmp vs uint64_t comparisson

时间:2018-02-18 14:05:57

标签: c++ c++11 strcmp memcmp

我有很多字符串,每个字符串大小不超过8个。

我需要使用memcmp() / strcmp()进行大量比较。

我想知道如果将所有比较转换为std::uint64_t,比较是否会更快。在这种情况下,至少理论上的比较将是无分支的,也会在单CPU操作中发生。

有没有人尝试过类似的东西?

以下是生成这些数字的一些测试代码。我假设小端机器。

如果我使用htobe32() / htobe64(),我知道代码可以大大简化。

#include <cstdint>

#include <algorithm>    // std::reverse_copy

namespace rev_impl{
    template<typename T>
    T rev(const char *s){
        T t;
        char *pt = reinterpret_cast<char *>(&t);

        std::reverse_copy(s, s + sizeof(T), pt);

        return t;
    }
}

inline uint32_t rev32(const char *s){
    return rev_impl::rev<uint32_t>(s);
}

inline uint64_t rev64(const char *s){
    return rev_impl::rev<uint64_t>(s);
}


#include <iostream>
#include <iomanip>

template<typename T>
void print_rev(const char *s){
    constexpr auto w = sizeof(T) * 2;

    std::cout << std::setw(w) << std::setfill('.') << std::hex << rev_impl::rev<T>(s) << '\n';
}

inline void print_rev32(const char *s){
    return print_rev<uint32_t>(s);
}

inline void print_rev64(const char *s){
    return print_rev<uint64_t>(s);
}

int main(){
    print_rev64("\0\0\0\0\0\0\0a");
    print_rev64("a\0\0\0\0\0\0\0");

    print_rev32("Niki");
    print_rev32("Nika");
    print_rev32("Nikz");
}

这是测试输出:

..............61
6100000000000000
4e696b69
4e696b61
4e696b7a

1 个答案:

答案 0 :(得分:0)

如果您只需要转换字符串文字,可以编写rev以接受char的数组,如下所示

template <typename T, std::size_t N,
          typename = typename std::enable_if<(N<=sizeof(T)+1U)>::type>
constexpr T rev (char const (&arr)[N])
 {
   T ret = 0;

   std::size_t  ui = -1;

   while ( ++ui < N-1U )
      ret <<= CHAR_BIT, ret |= arr[ui];

   while ( ++ui < sizeof(T) )
      ret <<= CHAR_BIT;

   return ret;
 }

请注意,从C ++ 14开始,可以定义此函数constexpr,因此您可以编写一些内容

constexpr auto fb = rev<std::uint64_t>("foobar");

以下是您重写的代码以使用字符串文字

#include <cstdint>
#include <climits>
#include <iostream>
#include <iomanip>
#include <type_traits>

namespace rev_impl
 {
    template <typename T, std::size_t N,
              typename = typename std::enable_if<(N<=sizeof(T)+1U)>::type>
    T rev (char const (&arr)[N])
     {
       T ret = 0;

       std::size_t  ui = -1;

       while ( ++ui < N-1U )
          ret <<= CHAR_BIT, ret |= arr[ui];

       while ( ++ui < sizeof(T) )
          ret <<= CHAR_BIT;

       return ret;
     }
 }

template <typename T, std::size_t N>
inline uint32_t rev32 (char const (&s)[N])
 { return rev_impl::rev<uint32_t>(s); }

template <typename T, std::size_t N>
inline uint64_t rev64 (char const (&s)[N])
 { return rev_impl::rev<uint64_t>(s); }

template<typename T, std::size_t N>
void print_rev (char const (&s)[N])
 {
   constexpr auto w = sizeof(T) * 2;

   std::cout << std::setw(w) << std::setfill('.') << std::hex
      << rev_impl::rev<T>(s) << '\n';
 }

template <std::size_t N>
inline void print_rev32 (char const (&s)[N])
 { return print_rev<uint32_t>(s); }

template <std::size_t N>
inline void print_rev64 (char const (&s)[N])
 { return print_rev<uint64_t>(s); }

int main ()
 {
   print_rev64("\0\0\0\0\0\0\0a");
   print_rev64("a\0\0\0\0\0\0\0");

   print_rev32("Niki");
   print_rev32("Nika");
   print_rev32("Nikz");
 }