字节向量到整数类型:通过联合移位和添加或隐式转换?

时间:2016-12-07 22:56:01

标签: c++ arrays int type-conversion cbor

我目前正在实现CBOR并且需要从字节数组中重复读取1,2,4或8个字节,然后需要将这些字节组合成1,2,4或8字节的整数类型

对于4字节的情况,我目前使用此模板函数(vec是我正在读取的字节向量,current_idx标记向量中的位置,我想从哪里开始读取4个字节):

template<typename T, typename std::enable_if<sizeof(T) == 4, int>::type = 0>
static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_idx)
{
    return static_cast<T>((static_cast<T>(vec[current_idx]) << 030) +
                          (static_cast<T>(vec[current_idx + 1]) << 020) +
                          (static_cast<T>(vec[current_idx + 2]) << 010) +
                          static_cast<T>(vec[current_idx + 3]));
}

(对于1,2和8字节的情况,我有三个类似的函数。)

示例调用将是

std::vector<uint8_t> vec {0x01, 0x00, 0x00, 0xff};
auto num = get_from_vector<uint32_t>(vec, 0);
assert(num == 0x10000FF);

虽然性能似乎不是问题,但我想知道以下代码是否更有效或至少更具可读性:

template<typename T, typename std::enable_if<sizeof(T) == 4, int>::type = 0>
static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_idx)
{
    union U
    {
        T result_type;
        uint8_t bytes[4];
    } u;
    u.bytes[3] = vec[current_idx];
    u.bytes[2] = vec[current_idx + 1];
    u.bytes[1] = vec[current_idx + 2];
    u.bytes[0] = vec[current_idx + 3];
    return u.result_type;
}

对此有何想法?

1 个答案:

答案 0 :(得分:1)

我个人更喜欢你的第二选择(使用工会),因为它似乎更快,更易读。

但还有另一种定义函数的方法:使用指针。一个好处是你只需要定义一个函数而不是重载它。

template<typename T>
static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_index){
    T result;
    uint8_t *ptr = (uint8_t *) &result;
    size_t idx = current_index + sizeof(T);
    while(idx > current_index)
        *ptr++ = vec[--idx];
    return result;
}

更改您的通话示例:

int main(){
    std::vector<uint8_t> vec {0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xff};

    auto byte1 = get_from_vector<uint8_t>(vec, 3);
    assert(byte1 == 0xff);

    auto byte2 = get_from_vector<uint16_t>(vec, 3);
    assert(byte2 == 0xff01);

    auto byte4 = get_from_vector<uint32_t>(vec, 4);
    assert(byte4 == 0x010000ff);

    auto byte8 = get_from_vector<uint64_t>(vec, 0);
    assert(byte8 == 0x010000ff010000ffUL);
}