char -> unsigned char -> char



  • also das übliche verfahren wäre doch so:

    /* C */
    char blub = 'Ä';
    unsigned char u_blub = *((unsigned char*)&blub);
    char blub2 = *((char*)&u_blub);
    
    // C++
    char foo = 'ä';
    unsigned char bar = *(reinterpret_cast<unsigned char*>(&foo));
    char foo2 = *(reinterpret_cast<char*>(&bar));
    

    oder?

    also zumindest funktioniert das immer...


  • Mod

    hustbaer schrieb:

    @camper:
    Bist du sicher dass das mit den Referenzen OK geht?
    Ich hätte hier Zeiger verwendet...

    sorry, falsch gelesen, ich meinte so etwas wie

    char a = 'A';
    const unsigned char& b = reinterpret_cast<unsigned char const &>(a);
    const char& c = reinterpret_cast<char const &>(b);
    

    Ohne Referenzinitialisierung steht da nat. im Anschluss zum Cast eine l-zu-rvalue Konvertierung, mithin ein Zugriff, für den 3.10/15 zuständig ist.

    Ansonsten ist das genau so wie ich das auch immer tun würde. Zum Einen hat das Ganze nichts mit Zeigern als Solchen zu tun, zudem funktioniert die Zeigervariante nicht, sobald ein überladener &-Operator im Spiel ist.
    Ich habe nichts gegen die C-Variante, dort geht das nicht anders; für C++ sieht reinterpret_cast+Zeiger immer ein wenig wie gewollt und nicht gekonnt aus.



  • hustbaer schrieb:

    @camper:
    Bist du sicher dass das mit den Referenzen OK geht?
    Ich hätte hier Zeiger verwendet...

    5.2.10 §10 beschreibt ja gerade die Sache mit den Referenzen. Allerdings ist da von lvalues und casts auf T& und nicht auf T const & die Rede. Ich bin mir da nicht sicher, ob const von §2 abgedeckt wird.

    Danke auf jeden Fall erstmal.



  • @Tachyon:
    Öh.
    Du willst doch hier Werte konvertieren (nicht Referenzen erzeugen), oder?
    Und halt so dass der "Round Trip" von "char" zu "unsigned char" zu "char" verlustfrei bleibt.

    mMn. ist das ein Fall für memcpy() bzw. Kopieren mittels "unsigned char*".

    Also kurz gesagt, ich hätte es so gemacht wie DrakoXP (C++ Variante).

    Der überladene operator & ist ja kein Ding bei eingebauten Typen wie char/unsigned char.



  • krümelkacker schrieb:

    Außerdem darf man jedes POD-Objekt über unsigned char* "untersuchen".

    Man darf auch jedes Objekt (bzw. seinen Speicher -- auch nicht-PODs) über unsigned char* überschreiben.
    Von daher vermute ich mal dass man auch nicht-PODs über unsigned char* untersuchen darf.

    Anders herum wäre das möglicherweise problematischer, also unsigned char -> char -> unsigned char (per reinterpret_cast<T&>), da ein unsigned char mit Wert 128 ein ungültiges char-Bit-Muster sein könnte ("negative Null" in der Sign+Magnitude-Darstellung)

    Gilt die "jedes Bitmuster OK" Garantie nur für "unsigned char" und nicht für "char"?
    Würde mich jetzt etwas wundern, ich hab irgendwie in Erinnerung dass man auch mit nem "char*" jedes Objekt "untersuchen" darf - und das ginge ja nicht, wenn es für "char" ungültige Bitmuster gäbe...



  • hustbaer schrieb:

    @Tachyon:

    mMn. ist das ein Fall für memcpy() bzw. Kopieren mittels "unsigned char*"..

    Würde ich auch so machen, nur ist der Zieltyp von unsigned char -> char ein std::string , und da kann ich nicht einfach mit memcpy reinkopieren.



  • camper schrieb:

    3.10/15 spielt hier gar keine Rolle, da ja nicht mittels b auf den Wert von a zugegriffen wird

    Na klar spielt das eine Rolle. Mit b hat das nichts zu tun, aber der Ausdruck reinterpret_cast<char const&>(a) ist ein Lvalue-Ausdruck, der sich Speicher-technisch auf a bezieht, aber einen anderen Typ hat als a. 3.10/15 beschreibt und erlaubt diesen Fall (keine Aliasingprobleme bei char<->unsigned char). Und reinterpret_cast<T&>(x) ist äquivalent zu (*reinterpret_cast<T*>(&x)).

    hustbaer schrieb:

    Gilt die "jedes Bitmuster OK" Garantie nur für "unsigned char" und nicht für "char"?

    Ich denke schon, dass das gilt. Allerdings habe ich ein Problem mit anderen Zahlendarstellungsformen für negative Ganzzahlen, die mir theoretisch zwei Nullen bieten, "+0" und "-0":

    sign+magnitude  1's complement  "Wert"
    --------------------------------------
       00000000        00000000      "+0"
       10000000        11111111      "-0"
    

    Mit einem vorzeichenbehafteten char kann ich in so einem Fall anhand des Ganbzzahlwertes diese Bitmuster nicht mehr unterscheiden.

    Ich gehe aber zZ davon aus, dass, falls die Maschine eine solche "komische" Zahlendarstellung verwendet, char gar nicht vorzeichenbehaftet ist. Ein vorzeichenbehaftetes char kann man sich eigentlich nur mit dem Zweierkomplement erlauben -- denke ich mal.

    kk



  • Ich versteh euer Problem nicht.. Warum so hässliche Casts?

    #include <iostream>
    
    int main()
    {
            char a = 'a';
            unsigned char b = a;
            char c = b;
            std::cout << a << std::endl;
            std::cout << b << std::endl;
            std::cout << c << std::endl;
    }
    

    http://ideone.com/RCgMR


  • Mod

    krümelkacker schrieb:

    camper schrieb:

    3.10/15 spielt hier gar keine Rolle, da ja nicht mittels b auf den Wert von a zugegriffen wird

    Na klar spielt das eine Rolle. Mit b hat das nichts zu tun, aber der Ausdruck reinterpret_cast<char const&>(a) ist ein Lvalue-Ausdruck, der sich Speicher-technisch auf a bezieht, aber einen anderen Typ hat als a. 3.10/15 beschreibt und erlaubt diesen Fall (keine Aliasingprobleme bei char<->unsigned char). Und reinterpret_cast<T&>(x) ist äquivalent zu (*reinterpret_cast<T*>(&x)).

    Ja, ich hatte das bereits korrigiert.

    krümelkacker schrieb:

    hustbaer schrieb:

    Gilt die "jedes Bitmuster OK" Garantie nur für "unsigned char" und nicht für "char"?

    Ich denke schon, dass das gilt. Allerdings habe ich ein Problem mit anderen Zahlendarstellungsformen für negative Ganzzahlen, die mir theoretisch zwei Nullen bieten, "+0" und "-0":

    sign+magnitude  1's complement  "Wert"
    --------------------------------------
       00000000        00000000      "+0"
       10000000        11111111      "-0"
    

    Mit einem vorzeichenbehafteten char kann ich in so einem Fall anhand des Ganbzzahlwertes diese Bitmuster nicht mehr unterscheiden.

    Ich gehe aber zZ davon aus, dass, falls die Maschine eine solche "komische" Zahlendarstellung verwendet, char gar nicht vorzeichenbehaftet ist. Ein vorzeichenbehaftetes char kann man sich eigentlich nur mit dem Zweierkomplement erlauben -- denke ich mal.

    kk

    Weder C noch C++ verlangen, dass die Bitkombination 10000000 (Zweierkomplement oder sign+magnitude) bzw. 11111111 (Einserkomplement) - bzw. entsprechend länger wenn chars mehr als 8 bit haben - bei vorzeichenbehafteten chars ein Zahl ist. In keinem Fall handelt es sich aber um eine Trapdarstellung, C99:6.2.6.2/5 bezieht sich nur auf Typen, die keine Zeichentypen sind.

    Wenn (in einer bestimmten Implementation) Einserkomplement oder sign+magnitude verwendet wird und die obigen Objektdarstellungen eine Zahl darstellen so handelt es sich um eine negative Null. Rechenregeln und anderes dazu findet sich im C-Standard (C99:6.2.6.2/3).


  • Mod



  • Achso, jetzt wird mir alles klar. 🤡


Anmelden zum Antworten