Buffer: std::vector<char> vs. std::vector<__int8>/std::vector<std::tr1::int8_t>



  • Roger Wilco schrieb:

    Ach so, sollte man eigentlich char oder lieber unsigned char nehmen...? *grübel* Eigentlich vollkommen egal, oder?

    Finde ich nicht egal. Selbst wenn es in Produktion keinen Unterschied macht, ist unsigned char semantisch eindeutiger. Es gibt diese Abstraktionen und Hi-Level-Sprachen, um die Wartung zu vereinfachen. Auch wenn man Monate später sich den Code anschaut, sollte man mit Code ausdrücken, was man meint. Also, es ist nicht egal!



  • 7.20.1.1 Exact-width integer types
    1 The typedef name intN_t designates a signed integer type with width N, no padding
    bits, and a two’s complement representation. Thus, int8_t denotes such a signed
    integer type with a width of exactly 8 bits.
    2 The typedef name uintN_t designates an unsigned integer type with width N and no
    padding bits. Thus, uint24_t denotes such an unsigned integer type with a width of
    exactly 24 bits.

    aaaber "These types are optional."



  • ipsec schrieb:

    Nicht wirklich. char ist per Definition der kleinste Datentyp, und wenn der mehr als ein Byte hat, hat es int8_t auch.

    Nein, wenn CHAR_BIT != 8 dann wird es kein int8_t geben. int8_t ist nämlich ein optionaler "exact width" typedef. Es wird aber wohl ein int_least8_t geben.

    Bedenke auch, dass es 3 char-Typen gibt. char, signed char und unsigned char. int8_t ist typischerweise ein typedef für "signed char".

    Benutze einfach char (oder vielleicht unsigned char) und füge deinem Code ein

    #include <climits>
    #if CHAR_BIT != 8
    #error "Diese Implementierung erwartet CHAR_BIT==8."
    #endif
    

    falls Du Dich auf CHAR_BIT==8 verlässt.

    kk



  • Danke für Euer Feedback! 🙂

    Artchi schrieb:

    Auch wenn man Monate später sich den Code anschaut, sollte man mit Code ausdrücken, was man meint. Also, es ist nicht egal!

    Stimmt, da hast Du recht.

    krümelkacker schrieb:

    Benutze einfach char (oder vielleicht unsigned char) und füge deinem Code ein

    #include <climits>
    #if CHAR_BIT != 8
    #error "Diese Implementierung erwartet CHAR_BIT==8."
    #endif
    

    Das klingt vernünftig. Andererseits, wenn ich einfach uint8_t (bzw. unsigned __int8 bei MSVC++) verwende und es gibt kein 8-Bit-Datentyp, dann würde er doch auch beim kompilieren meckern.



  • Ist das nicht Jacke wie Hose bei Empfangspuffern, ob ein char nur 1 o. 2 Byte auf dem System belegt? Welches Encoding nun wirklich genutzt wird kann man doch eh dann dem nächst höheren Protokolllayer entnehmen u. ggf. auf wchar_t (oder irgendwelche Datentypen für Multibyte/Unicode-Strings) casten. Hauptsache, man empfängt alle Bits, die 2 geteilten chars (wenn wchar_t mit 2 Byte gesendet wurde) klebt man dann einfach wieder in ein wchar_t zusammen.



  • Roger Wilco schrieb:

    Nun ist ja aber ein char nicht zwangsläufig ein Byte groß.

    Doch! Nur muss das nicht 8 Bit entsprechen.



  • Michael E. schrieb:

    Roger Wilco schrieb:

    Nun ist ja aber ein char nicht zwangsläufig ein Byte groß.

    Doch! Nur muss das nicht 8 Bit entsprechen.

    😕 Ich werde es wohl nie verstehen...

    Ich dachte: Ein char kann in C++ 256 Zustände annehmen (unsigned char: 0...255). Das entspricht dem "Verhalten" eines Bytes. Im Speicher kann aber ein char z.B. auch 16 Bit groß sein. Ein bool ist ja auch nicht nur ein Bit im Speicher, kann aber trotzdem nur true/false sein.

    Wie groß das in echt (im Speicher) ist interessiert mich bei C++ i.d.R. auch nicht. Wertebereiche sind da interessant.

    Aber: Wenn ich jetzt einen Sendepuffer habe und die Daten des Puffers verschicken will, dann versende ich ja die rohen Speicherinhalte und da ist die Größe dann doch wichtig.

    Oder bin ich da auf einem absoluten Holzweg...

    Bei mir geht es darum, dass ich gerade unabhängig von einer bestimmten Socket-Implementierung Sendedaten bereitstellen will (Serialisierung). Was nehm' ich dafür am besten? Andersherum will ich auch Daten empfangen und deserialisieren können.



  • Roger Wilco schrieb:

    Ich dachte: Ein char kann in C++ 256 Zustände annehmen (unsigned char: 0...255). Das entspricht dem "Verhalten" eines Bytes.

    Auf manchen Plattformen hat ein Byte nicht 8 Bit, und somit nicht zwangsweise 256 Zustände (und C++ orientiert sich in der Regel am System, nicht deiner Annahme). Ein Byte wird meistens synonym für 8 Bit verwendet, aber dies ist nur so, weil viele Systeme mit dieser Größe arbeiten. Siehe hierzu auch den Wikipedia-Artikel



  • 😮 Oh. Ok, das wusste ich nicht.

    Gut, das Problem lässt sich also so formulieren:

    Wenn ich Daten über einen Puffer senden/empfangen will und es ist festgelegt, dass ein Byte 8 Bit besitzen muss: wie gestallte ich am besten den Sende- und Empfangspuffer, wenn ich einzelne Bytes (8 Bit) senden und empfangen möchte?



  • Darf ich nochmal nachfragen:

    Wenn Ihr also zwingend 8 Bit-Bytes senden müsst. Welche Variante würdet Ihr nehmen:

    #include <climits>
    #if CHAR_BIT != 8
    #error "Diese Implementierung erwartet CHAR_BIT==8."
    #endif
    
    std::vector<unsigned char> buffer;
    
    #include <cstdint>
    
    std::vector<unint8_t> buffer;
    


  • Roger Wilco schrieb:

    Wenn Ihr also zwingend 8 Bit-Bytes senden müsst. Welche Variante würdet Ihr nehmen:

    Das hört sich vielleicht merkwürdig, gerade nach meinen Vorpost an: Ich würde die char!=8 Bit Problematik ignorieren. Nicht, weil ich nicht weiß, das es Systeme gibt die eine andere Basis verwenden, sondern weil diese Systeme für mich (ich bin ausschließlich im PC-Umfeld tätig) irrelevant sind. Ich halte Portierbarkeit zwar nicht für verkehrt, aber die Frage ist, wie weiträumig man Portierbarkeit auslegt.

    Ich kenne kein System, das im "normalen" PC-Umfeld (mit einem gängigen Clientbetriebssystem) eine andere Basis als 8 Bit verwendet. Und Software im Embedded oder Großrechnerbereich, erfordert meines Erachtens eh eine etwas andere Programmierung.



  • Danke asc für Deine Antwort!

    Grundsätzlich möchte ich versuchen mir einen portablen C++-Stil anzugewöhnen. Manchmal ist das ja einfacher, manchmal aber sehr aufwendig. Ich bin da auf Ausagen von Euch erfahrenen Programmieren angewiesen, die mir sagen, wann etwas Sinn macht und wann nicht.



  • Roger Wilco schrieb:

    Ich bin da auf Ausagen von Euch erfahrenen Programmieren angewiesen, die mir sagen, wann etwas Sinn macht und wann nicht.

    Die Frage ist: Was sind deine Zielsysteme, und wann rentiert sich der Aufwand und wann nicht. In diesem Fall ist die Prüfung aber nur wenige Zeilen groß, so das es nicht schadet, diese einzubauen. Ob die Zeilen jedoch jemals relevant werden, ist eine andere Frage.

    Ich betrachte das Thema Portabilität nicht komplett, da ich selbst bei "Portabilität" in der Regel die Systeme schon eingrenzen kann. Mir ist derzeit kein verbreitetes System in meinem Zielbereich bekannt, wo ich diesen Sonderfall berücksichtigen müsste (Wäre mal schön, wenn jemand ein Beispiel für ein verbreitetes System jenseits des Embedded- und des Großrechnermarktes nennen kann, bei dem char != 8 Bit ist).



  • Wenn du vector<char> nimmst, brauchst du auch keine Überprüfung, weil es mit anderen Bytegrößen genauso funktioniert, es sei denn, du hast eine Codestelle, an der du zwingend voraussetzt, dass ein char genau 8 Bit hat.


Anmelden zum Antworten