Frage

Ich versuche, einen Datenstrom in eine Struktur zu werfen, da der Datenstrom von fester Breite Nachrichten besteht und jede Nachricht hat Fulle feste Breite Felder definiert als gut. Ich habe geplant, auf eine Struktur zu schaffen und dann reinterpret_cast mit Zeigern auf den Datenstrom auf die Struktur zu werfen, die Felder zu bekommen. Ich habe einige Test-Code und erhalten seltsame Ergebnisse. Könnte jeder erklären, warum ich diese oder, wie ich immer den Code zu korrigieren. (Der Datenstrom wird binär und alphanumerische gemischt, aber im nur mit Streichern Prüfung)

#pragma pack(push,1)
struct Header 
{
    char msgType[1];
    char filler[1];
    char third[1];
    char fourth[1];
};
#pragma pack(pop)

int main(void)
{
    cout << sizeof(Header) << endl;

    char* data = "four";
    Header* header = reinterpret_cast<Header*>(data);
    cout << header->msgType << endl;
    cout << header ->filler << endl;
    cout << header->third << endl;
    cout << header->fourth << endl;
    return 0;
}

Das Ergebnis, das nach oben kommen ist

4
four
our
ur
r

Ich denke, die vier, unsere und ur druckt, da es den Nullabschluss finden kann. Wie kann ich um den Nullabschluss Problem bekommen?

War es hilfreich?

Lösung

Um die Lage sein, eine Reihe von Zeichen zu drucken, und es unterscheiden zu können von einem nullterminierten String, müssen Sie andere operator<< Definitionen:

template< size_t N >
std::ostream& operator<<( std::ostream& out, char (&array)[N] ) {
     for( size_t i = 0; i != N; ++i ) out << array[i];
     return out;
}

Andere Tipps

Sie haben Recht über den Mangel an Nullabschluss. Der Grund, es ist Druck „ur“ wieder, weil Sie die Header- wiederholt> dritte statt Header-> Vierter. Anstelle von "char [1]", warum nicht nur diese Variablen als "char" erklären?

struct Header 
{
    char msgType;
    char filler;
    char third;
    char fourth;
};

Das Problem reinterpret_cast nicht (obwohl mit ihm eine sehr schlechte Idee ist), aber in der Art der Dinge, in der Struktur. Sie sollen vom Typ 'char', nicht vom Typ 'char [1]'.

#pragma pack(push,1)
template<int N>
struct THeader 
{
    char msgType[1+N];
    char filler[1+N];
    char third[1+N];
    char fourth[1+N];
};
typedef THeader<0> Header0;
typedef THeader<1> Header1;  
Header1 Convert(const Header0 & h0) {
   Header1  h1 = {0};
   std::copy(h0.msgType, h0.msgType + sizeof(h0.msgType)/sizeof(h0.msgType[0]), h1.msgType);
   std::copy(h0.filler, h0.filler+ sizeof(h0.filler)/sizeof(h0.filler[0]), h1.filler);
   std::copy(h0.third , h0.third + sizeof(h0.third) /sizeof(h0.third [0]), h1.third);
   std::copy(h0.fourth, h0.fourth+ sizeof(h0.fourth)/sizeof(h0.fourth[0]), h1.fourth);
   return h1;
}
#pragma pack(pop)


int main(void)
{
  cout << sizeof(Header) << endl;
  char* data = "four";
  Header0* header0 = reinterpret_cast<Header*>(data);
  Header1 header = Convert(*header0);
  cout << header.msgType << endl;
  cout << header.filler << endl;
  cout << header.third << endl;
  cout << header.fourth << endl;
  return 0;
}

Nach meiner Erfahrung hat mit #pragma pack Kopfschmerzen verursacht - teilweise aufgrund eines Compiler, der nicht richtig Pops, sondern auch durch Entwickler zu vergessen in einer Header-Pop. Ein Fehler, wie das und structs am Ende definiert unterschiedlich, je nach der um Header in einer Übersetzungseinheit enthalten bekommen. Es ist ein Debug-Alptraum.

Ich versuche, nicht-Speicher-Overlays aus diesem Grunde zu tun - man kann nicht darauf vertrauen, dass Ihre Struktur ordnungsgemäß mit den Daten ausgerichtet ist, die Sie erwarten. Stattdessen erstelle ich structs (oder Klassen), die die Daten aus einer Nachricht in einem „native“ C ++ Format enthält. Zum Beispiel, brauchen Sie nicht ein „Füllstoff“ Feld definiert, wenn sie für Zwecke der Ausrichtung gerade da ist. Und vielleicht macht es mehr Sinn für die Art eines Feldes als int wird, damit es char[4] werden. So bald wie möglich, übersetzt den Datenstrom in die „native“.

Angenommen, Sie möchten, halten Sie ein overlayable Struktur mit (was sinnvoll ist, da sie die Kopie in Alexey Code vermeidet), können Sie Ihre RAW-char-Arrays mit einem Wrapper wie folgt ersetzt werden:

template <int N> struct FixedStr {
    char v[N];
};

template <int N>
std::ostream& operator<<( std::ostream& out, FixedStr const &str) {
    char const *nul = (char const *)memchr(str.v, 0, N);
    int n = (nul == NULL) ? N : nul-str.v;
    out.write(str.v, n);
    return out;
}

Dann werden Ihre erzeugten Strukturen werden wie folgt aussehen:

struct Header 
{
    FixedStr<1> msgType;
    FixedStr<1> filler;
    FixedStr<1> third;
    FixedStr<40> forty;
};

und Ihr vorhandener Code sollte funktionieren.

NB. Sie können Methoden in den FixedStr, wenn Sie (zB std::string FixedStr::toString()) wollen einfach nicht hinzufügen virtuelle Methoden oder Vererbung, und es wird überlagern in Ordnung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top