12 Stimmen

C++ Beispiel für Coding Horror oder brillante Idee?

Bei einem früheren Arbeitgeber schrieben wir Binärnachrichten, die "über den Draht" an andere Computer geschickt werden mussten. Jede Nachricht hatte einen Standard-Header, etwa so:

class Header
{
    int type;
    int payloadLength;
};

Alle Daten waren zusammenhängend (Kopfzeile, unmittelbar gefolgt von den Daten). Wir wollten an die Nutzdaten gelangen, da wir einen Zeiger auf einen Header hatten. Traditionell könnte man etwas sagen wie:

char* Header::GetPayload()
{
    return ((char*) &payloadLength) + sizeof(payloadLength);
}

oder sogar:

char* Header::GetPayload()
{
    return ((char*) this) + sizeof(Header);
}

Das schien mir etwas zu langatmig, also habe ich mir etwas ausgedacht:

char* Header::GetPayload()
{
    return (char*) &this[1];
}

Auf den ersten Blick wirkt es eher beunruhigend, vielleicht zu seltsam für den Gebrauch - aber sehr kompakt. Es gab eine Menge Debatten darüber, ob es brillant oder eine Abscheulichkeit ist.

Also, was ist es - Verbrechen gegen die Codierung oder eine gute Lösung? Hatten Sie jemals einen ähnlichen Kompromiss?

-Update:

Wir haben das Array mit der Größe Null ausprobiert, aber damals gaben die Compiler Warnungen aus. Wir sind schließlich zur inhärenten Technik übergegangen: Message leitet sich von Header ab. Das funktioniert in der Praxis gut, aber im Prinzip sagen Sie, dass eine Nachricht ein Header ist - was ein wenig umständlich ist.

14voto

Menkboy Punkte 1565

Ich persönlich denke, wenn es ein Verbrechen gibt, dann ist es die Frage nach der Kopfzeile und der Nutzlast.

Aber wenn Sie es auf diese Weise machen wollen, ist "this+1" so gut wie jeder andere Weg.

Begründung: '&this[1]' ist ein universell einsetzbarer Code, bei dem man sich nicht durch Klassendefinitionen wühlen muss, um ihn vollständig zu verstehen, und der nicht korrigiert werden muss, wenn jemand den Namen oder den Inhalt der Klasse ändert.

Das erste Beispiel ist übrigens das wahre Verbrechen gegen die Menschheit. Fügen Sie ein Mitglied am Ende der Klasse hinzu und es wird scheitern. Verschieben Sie die Mitglieder innerhalb der Klasse und es wird scheitern. Wenn der Compiler die Klasse auffüllt, wird sie scheitern.

Wenn Sie außerdem davon ausgehen, dass das Layout der Klassen/Strukturen des Compilers mit dem Layout Ihres Pakets übereinstimmt, sollten Sie verstehen, wie der betreffende Compiler arbeitet. Z.B. bei MSVC werden Sie wahrscheinlich wissen wollen, wie #pragma pack .

PS: Es ist ein wenig beängstigend, wie viele Leute "dies+1" oder "&dies[1]" für schwer zu lesen oder zu verstehen halten.

14voto

tvanfosson Punkte 506878

Sie sind davon abhängig, dass der Compiler Ihre Klassen auf eine bestimmte Weise anordnet. Ich hätte die Nachricht als struct definiert (wobei ich das Layout definiere) und eine Klasse, die die Nachricht kapselt und die Schnittstelle zu ihr bereitstellt. Klarer Code = guter Code. "Niedlicher" Code = schlechter (schwer zu wartender) Code.

struct Header
{
    int type;
    int payloadlength;
}
struct MessageBuffer
{
   struct Header header;
   char[MAXSIZE] payload;
}

class Message
{
  private:
   MessageBuffer m;

  public:
   Message( MessageBuffer buf ) { m = buf; }

   struct Header GetHeader( )
   {
      return m.header;
   }

   char* GetPayLoad( )
   {
      return &m.payload;
   }
}

Es ist eine Weile her, dass ich C++ geschrieben habe, also entschuldigen Sie bitte eventuelle Probleme mit der Syntax. Ich versuche nur, die allgemeine Idee zu vermitteln.

13voto

Roddy Punkte 64661

Das ist ein häufiges Problem, aber was Sie eigentlich wollen, ist Folgendes.

class Header
{
    int type;
    int payloadLength;
    char payload[0];

};

char* Header::GetPayload()
{
    return payload;
}

5voto

Tom Ritter Punkte 97450

Meine Stimme ist Coding Horror. Verstehen Sie mich nicht falsch, es ist schlau - aber Sie sparen sich einen ganzen Additionsvorgang um den Preis, dass der Code viel schwerer zu verstehen und zu lesen ist. Ich finde, der Kompromiss ist es nicht wert.

5voto

ypnos Punkte 47895

Ich denke, dass dies von Anfang an fehlerhaft ist, wenn die Kopfzeile Daten "zurückgeben" muss, die nicht in ihr enthalten sind.

Da Sie sich bereits auf diese hakeligen Gründe eingelassen haben, finde ich es wirklich toll, was Sie sich ausgedacht haben.

Aber beachten Sie, dass es sich hier nicht um einen Schönheitswettbewerb handelt. Sie sollten eine ganz andere Lösung finden. Bei allen drei Versionen von GetPayload(), die Sie vorgestellt haben, würde ich ohne Ihre weitere Erklärung nicht verstehen, was zum Teufel da los ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X