2016-07-19 17 views
0

Ich möchte eine 64-Bit-Elementvariable Byte für Byte in einen Vektor kopieren.Kopiere Member-Variable in Byte-Vektor

Bitte vermeiden Sie mir, Bit-Operation zu verwenden, um jedes Byte zu extrahieren und sie dann in Vektor zu kopieren.

Ich möchte dies durch eine Zeile tun.

Ich benutze memcpy und kopieren Methoden, aber beide fehlgeschlagen. Hier

ist der Beispielcode:

#include <iostream> 
#include <vector> 
#include <cstdint> 
#include <cstring> 

using namespace std; 

class A { 
public: 
    A() 
    : eight_bytes_data(0x1234567812345678) { 
    } 

    void Test() { 
    vector<uint8_t> data_out; 
    data_out.reserve(8); 
    memcpy(data_out.data(), 
      &eight_bytes_data, 
      8); 
    cerr << "[Test]" << data_out.size() << endl; 
    } 

    void Test2() { 
    vector<uint8_t> data_out; 
    data_out.reserve(8); 
    copy(&eight_bytes_data, 
     (&eight_bytes_data) + 8, 
     back_inserter(data_out)); 
    cerr << "[Test2]" << data_out.size() << endl; 
    for (auto value : data_out) { 
     cerr << hex << value << endl; 
    } 
    } 

private: 
    uint64_t eight_bytes_data; 
}; 

int main() { 
    A a; 
    a.Test(); 
    a.Test2(); 
    return 0; 
} 
+0

'std :: vector <> :: reserve' nur Raum zuordnet, es sagt nicht, den Vektor, wie Viele Elemente werden in den Vektor eingefügt. Und da Sie memcpy verwenden, um das eigentliche Kopieren auszuführen, weiß der Vektor nicht, dass die kopierten Bytes jetzt verwendet werden. – evan

+1

Ein Teil des Fehlers im ersten Fall ist Ihr Verständnis davon, wie 'reserve()' funktioniert und wie es den zugrunde liegenden Vektor beeinflusst. Und im zweiten Fall ist Typed-Pointer-Arithmetik entscheidend, um zu verstehen, wo die Räder von dort abfielen. '(& acht_bytes_data) + 8' ist nicht acht Bytes nach der Basisadresse von' acht_bytes_data', seinen acht 'uint64_t' Elementen (und ziemlich tief in das Land von * undefiniertem Verhalten *, da du nur * ein * solches Element hast) . – WhozCraig

+0

@evan Ich verwende 'resize()', um 'reserve()' im ersten Fall zu ersetzen. Es klappt. – Christophe

Antwort

2

Da die anderen bereits zeigten, wo Sie falsch lagen, gibt es eine Ein-Linien-Lösung, die gefährlich ist.

Zuerst müssen Sie sicherstellen, dass der Vektor genügend Größe hat, um 8 Bytes zu empfangen. Etwas wie folgt aus:

data_out.resize(8); 

Das können Sie einen reinterpret_cast tun Compiler zu zwingen, diese 8 Bytes aus dem Vektor zu interpretieren als eine einzigartige Art von 8 Bytes zu sehen, und machen Sie die Kopie

*(reinterpret_cast<uint64_t*>(data_out.data())) = eight_bytes_data; 

Ich kann nicht alle Möglichkeiten erkennen, dass etwas schief läuft. So verwenden Sie auf eigene Gefahr.

+0

Vielen Dank für Ihre Lösung. Ich hab es geschafft. Können Sie mir bitte sagen, wie ich den zweiten Fall modifizieren soll, damit es funktioniert? Vielen Dank. – Christophe

+0

@Christophe Wie WhozCraig sagte, sind deine Typen falsch. Um sie zu korrigieren, müssen Sie die gleiche gefährliche Operation wie hier durchführen. Sie müssen Ihre int64_t als int8_t neu interpretieren. Etwas gefällt mir: 'copy (reinterpret_cast (& acht_bytes_data), reinterpret_cast (& acht_bytes_data) + 8, back_inserter (data_out));' – Amadeus

+2

Die 'std :: copy' ist eine verdammt viel sicherer als die direkte Zuweisung. Direkte Zuweisung zu einem Puffer, den Sie den Compiler überzeugen, ist ein Uint64_t (die Ausrichtungsbeschränkungen auf der Zielplattform haben kann) spielt mit Feuer in Bezug auf Portabilität. Das Ein-Byte-Kopieren in eine 'uint8_t'-Zielsequenz funktioniert und führt nicht zu dem Potential einer Panik. – WhozCraig

2

Wenn Sie mit den Bytes eines anderen Typs Struktur arbeiten, könnten Sie eine char * verwenden, um jedes Byte zu manipulieren:

void Test3() 
{ 
    vector<uint8_t> data_out; 
    char* pbyte = (char*)&eight_bytes_data; 

    for(int i = 0; i < sizeof(eight_bytes_data); ++i) 
    { 
     data_out.push_back(pbyte[i]); 
    } 

    cerr << "[Test]" << data_out.size() << endl; 

}

Leider haben Sie eine One-Line-Lösung angefordert, die ich nicht für realisierbar halte.

+1

Vielen Dank für Ihre Hilfe. Aber ich finde eine prägnantere Lösung. – Christophe

0

Wenn Sie in mehr generische Version Interesse:

namespace detail 
{ 
    template<typename Byte, typename T> 
    struct Impl 
    { 
     static std::vector<Byte> impl(const T& data) 
     { 
       std::vector<Byte> bytes; 
       bytes.resize(sizeof(T)/sizeof(Byte)); 
       *(T*)bytes.data() = data; 
       return bytes; 
     } 
    }; 

    template<typename T> 
    struct Impl<bool, T> 
    { 
     static std::vector<bool> impl(const T& data) 
     { 
      std::bitset<sizeof(T)*8> bits(data); 
      std::string string = bits.to_string(); 
      std::vector<bool> vector; 
      for(const auto& x : string) 
       vector.push_back(x - '0'); 
      return vector; 
     } 
    }; 
} 

template<typename Byte = uint8_t, 
     typename T> 
std::vector<Byte> data_to_bytes(const T& data) 
{ 
    return detail::Impl<Byte,T>::impl(data); 
} 

int main() 
{ 
    uint64_t test = 0x1111222233334444ull; 

    for(auto x : data_to_bytes<bool>(test)) 
     std::cout << std::hex << uintmax_t(x) << " "; 
    std::cout << std::endl << std::endl; 

    for(auto x : data_to_bytes(test)) 
     std::cout << std::hex << uintmax_t(x) << " "; 
    std::cout << std::endl << std::endl; 

    for(auto x : data_to_bytes<uint16_t>(test)) 
     std::cout << std::hex << uintmax_t(x) << " "; 
    std::cout << std::endl << std::endl; 

    for(auto x : data_to_bytes<uint32_t>(test)) 
     std::cout << std::hex << uintmax_t(x) << " "; 
    std::cout << std::endl << std::endl; 

    for(auto x : data_to_bytes<uint64_t>(test)) 
     std::cout << std::hex << uintmax_t(x) << " "; 
    std::cout << std::endl << std::endl; 

} 

Ausgang:

0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 1 
0 0 0 1 0 0 0 1 0 0 0 1 0 0 

44 44 33 33 22 22 11 11 

4444 3333 2222 1111 

33334444 11112222 

1111222233334444 
+0

Wir freuen uns, diese leistungsstarke Lösung zu sehen. Vielen Dank – Christophe