Char als 32-Bit fix



  • Hallo an alle,

    aus historischen Gründen wurde bei uns ein char als 32-Bit festgelegt (angeblich auf alten DSP war ein char 4 Bytes groß).

    Nun benutzen wir ein Framework, welches diese Größe fix erwartet.

    Nach mehreren Crashs wurde mir nun vom Framework-Entwickler mitgeteilt, dass das Problem in meinem Code wäre.

    Wenn ich ein Paket bekomme mit der Größe 100, dann allokiere ich ein Array mit der Größe 100 * sizeof(char). Später übergebe ich das Array an das Framework.

    unsigned char* pTransportBlock = new unsigned char[uiByteLength];
    

    Sein Framework erwartet allerdings, dass das Array 400 Bytes (char == 4 Byte) lang ist und die Größe 100 ist.

    Sein Vorschlag ist nun

    unsigned char* pTransportBlock = new unsigned char[uiByteLength * sizeof(int)];
    

    Mein Einwand, dass sowohl ein char größer als 1 und ein int auch kleiner als 4 sein kann und dann das Verhalten wieder undefiniert ist und der Code auch nicht portable ist, wurde mit dem logischen Argument: "Das machen wir schon immer so!" abgeschmettert.

    Welche Möglichkeit habe ich nun während der Laufzeit herauszufinden wie groß ein char ist und dann den Wert auf 4 Bytes zu bringen, falls er das noch nicht ist.

    Ich dachte, falls möglich an eine Lösung mit numeric_limits.

    Danke schon mal für eure Hilfe.

    Gruß
    Markus



  • Du könntest den Typ std::uint32_t aus dem Header <cstdint> verwenden, der ist garantiert 32 Bits groß.



  • 😕

    5.3.3 Sizeof [expr.sizeof]
    The sizeof operator yields the number of bytes in the object representation of its operand. The operand
    1
    is either an expression, which is not evaluated, or a parenthesized type-id. The sizeof operator shall not
    be applied to an expression that has function or incomplete type, or to an enumeration type before all its
    enumerators have been declared, or to the parenthesized name of such types, or to an lvalue that designates
    a bit-field. sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1; the
    result of sizeof applied to any other fundamental type (3.9.1) is implementation-defined. [Note: in par-
    ticular, sizeof(bool) and sizeof(wchar_t) are implementation-defined.69) ] [Note: See 1.7 for
    the definition of byte and 3.9 for the definition of object representation. ]



  • Oh, ich merke grad, uint32_t ist aus Boost, falls es das bei dir nicht gibt, mach's so (oder so ähnlich):

    #if ULONG_MAX == 0xFFFFFFFF
    	typedef unsigned long big_char_t;
    #elif UINT_MAX == 0xFFFFFFFF
    	typedef unsigned int big_char_t;
    #else
    	#error "No type of 32-bit-size found!"
    #endif
    

    Und das Array würde ich dann so behandeln (auch eben mit dem richtigen Typ!):

    big_char_t* arr = new big_char_t[length];
    


  • lord.hong schrieb:

    ...
    Welche Möglichkeit habe ich nun während der Laufzeit herauszufinden wie groß ein char ist ....

    Wie schon von "langeweile" angedeutet: Ist einfach, ist immer 1 (per definitionem).

    lord.hong schrieb:

    ...
    dann den Wert auf 4 Bytes zu bringen, falls er das noch nicht ist....

    Gar keine.
    Allerdings (und das würde ich in Deinem Fall unbedingt machen) kannst Du Dir Deinen eigenen "Charaktertyp" definieren, der dann intern auch 4 Byte hält und (über einen passenden getter) entsprechend 4 Byte rausgibt, wenn es das Kommunikationsprotokoll verlangt.

    Wenn man sich ein wenig Gedanken und Mühe macht, müsste man den sogar std::basic_string unterschieben können, so dass dann Zeichenketten genauso verarbeitet werden können wie mit std::string (=std::basic_string<char>).

    Als erster Schritt wäre aber schonmal "sinnvoll" (so, wie es "sinnvoll" ist, bei 140kmh einen Sicherheitsgurt anzulegen ;)), zu unterscheiden zwischen:

    • den C++-Standardtypen und
    • Typen eines selbst definierten Protokolls.

    (und zu dieser Unterscheidung gehören auch klar definierte Schnittstellen)
    Merke: Selbst wenn Du jetzt irgendeinen Weg zusammengefrickelt bekommen solltest, der erstmal funktioniert, wirst Dich (min.) in die 2 klassischen Problemen verheddern:
    1.) Der "Trick" funktioniert plötzlich nicht mehr, wenn man mit anderen Optionen , Versionen, Plattformen, .... kompiliert.
    2.) Eher früher als später verlierst Du den Überblick, wann Du jetzt mit einem "char" arbeitest und wann mit einem "char". 😉

    Gruß,

    Simon2.



  • Hallo Simon,

    das mit dem ein Byte für einen Character wusste ich noch nicht. Ich dachte immer mind. 1 Byte.

    Die Sache funktionert ja auch nur, weil sowohl auf Linux als auch auf Windows typeof(int) 4 ergibt.

    Das Argument ist ja auch, dass auf uralten DSP der Character 4 Bytes groß ist/war.

    Ich bin mir auch im klaren, dass ich mich nun dem Framework anpasse, was ich auch gar nicht möchte. Allerdings kann ich aber auch nicht erwarten, dass jemand der noch nicht mal weiß, was ein Objekt ist, bzw. dass es eine C++ Spec gibt, von heute auf morgen seinen Programmierstil ändert.

    Erstmal Danke an alle.

    Markus



  • Badestrand schrieb:

    Oh, ich merke grad, uint32_t ist aus Boost

    Genau gesagt ist uint32_t (bzw. sind alle [u]intX_t) zwar im Standard enthalten, aber optional. Deshalb gibt es die nicht überall.



  • falls es dir hilft: du kannst überprüfen, wieviele bits in deinem char zur verfügung stehen - mit numeric_limits<unsigned char>::digits (unsigned, weil das vorzeichenbit nicht mitgezählt wird)



  • Nun benutzen wir ein Framework, welches diese Größe fix erwartet.

    Nen framework hat Schnittstellen, und diese muessen ja irgendwie beschrieben sein ...

    Steht da irgend was drinne, das da ein Block von 4 byte .... musst du nen 4 byte datentyp definieren ....
    Fast alle compiler bieten interne datentypen mit definierter genaueigkeit an ... oder das BS (Posix) schreibt sowas vor.
    uint32_t unter unixe, und __uint32 unter windows z.b.

    mit compilerdirektiven kann man da header bauen die fuer mehrere BS / Compiler etc den richtigen code generieren.

    Ich wuerds definitiv typedefen ... damit mans an zentraler stelle hat ....

    und intern immer schoen mit sizeof arbeiten, also immer davon ausgehen das der datentyp mal die (relative) groesse (zu nem anderen datentyp) aendern kann.

    sizeof(int) == 4 ist ne gefaehrliche sache ...
    Ich wuerd mir mal nen template schreiben, wo bei sizeof(int) !=4 ne compiler exeption geworfen wird ^^ dann kannst gleich von ausgehen, das sein framework, oder die komponenten halt von den anderen, nimmer korrekt funktionieren werden ...

    Ciao ...



  • In den FAQs gibt es hier übrigens einen Thread zum Thema. Dort wird eine portable, also compilerunabhängige, Lösung vorgestellt, welche es ohne externe Abhängigkeiten erlaubt, auf Typen mit einer bestimmten Anzahl an Bits zuzugreifen. Das sieht dann ungefähr wie folgt aus:

    // 16 Bit unsigned Integer
    typedef select_integer<16, false>::result uint16;
    
    // 32 Bit signed Integer
    typedef select_integer<32, true>::result sint32;
    

    Bis <cstdint> offiziell in den Standard übernommen wurde, also nicht nur im TR1 Entwurf, könnte das recht hilfreich sein.


Anmelden zum Antworten