2016-12-07 2 views
1

私は現在、CBORを実装しています。バイト配列から1,2,4、または8バイトを繰り返し読み込む必要があります.1バイト、2バイト、4バイト、または8バイトの整数型に結合する必要があります。バイト型から整数型へ:ユニオンによるシフト、追加または暗黙の変換?

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])); 
} 

は、4バイトの場合のために、私は現在、(current_idxが、私は4バイトの読み取りを開始する場所からのベクトル内の位置をマークし、vec私はから読んでいたバイトのベクトルである)、このテンプレート関数を使用します

(Iは、それぞれ、1、2の場合のための3つの同様の機能、及び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

一般的に動作しますが、それはあなたにとって重要かどうUBは、あるタイプpunningのための組合を使います。別の問題では、それは私が長い間に8進法で見た最初の合理的な使用です;) –

+0

Unionのこの種の使用はUBです@IanM_Matrix1と述べました。しかし、それはほとんどのコンパイラで動作します。もし私が間違っていないとすれば、GCCの文書では、このタイプのUBを例外として扱われるタイプ・ペニングのための組合の使用について明示的に言及しています。 –

+0

ちょうど 'T resultのようなものがあるのはなぜですか? uint8_t * res_ptr = reinterpret_cast (&result); * result ++ = vec [current_idx + 3]; ...? – akappa

答えて

1

個人的に私はあなたの第2の選択肢(組合を使用して)を好みます。なぜなら、それは少し速くて読みやすいからです。

しかし、あなたの関数を定義する別の方法があります:ポインタを使う。利点は、関数をオーバーロードする代わりに、関数を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); 
} 
+0

ありがとう - これは私のために働く! –

関連する問題