Ist dieses Codefragment "Endian-Safe"?



  • Guten Tag,

    ich hab eine itoa Funktion geschrieben für eine Art Hausaufgabe:

    static uint32_t itoa_dot(uint8_t input){
        uint8_t output[4];
        output[3] = '.';
        int digits = 3;
        while(digits--){
            output[digits] = (input%10)|'0'; /* konvertierung zu ASCII */
            input /= 10;
        }
        return *((uint32_t*)output);
    }
    

    Wenn ich also 255 als input nehme, kommt ein {'2','5','5','.'} Array raus, dass dann gecastet wird.

    Für mein Little Endian System klappt es, und nach meiner Logik eigentlich auch für Big-Endiansysteme.
    Mich wundert es eher, dass der cast beim return nichts an der Bytereihenfolge ändert.
    Ist das so Portable?

    Mit freundlichen Grüßen,
    Thez



  • Wie greifst du auf die Daten wieder zu?

    Mit einem + '0' wäre es noch portabler.

    Warum der Mist?



  • Ich konvertiere eine Networkbyteorder in_addr_t in das dottet-Format. Ich soll explizit keine Funktionen irgendeiner Library benutzen.
    Also fallen auch printf-Varianten weg.

    Die Funktion, die diese hier aufruft, verwaltet ein int32_t[4] Objekt, in welches ich je nach System die Rückgaben der itoa_dot Funktion einordne.

    Am Ende füg ich das '\0' Byte hinzu, geb nen char* auf das Objekt zurück und alles ist gut.



  • C-style casts ändern soviel ich weiss nie was am Speicherlayout.
    Das ist einfach eine andere Reinterpretaion dessen was da an der Adresse steht.
    So wie es aussieht missbrauchst Du uint32_t hier einfach als Zwischenspeicher für ein 4-Byte-Array?
    Ich bin mr nicht ganz sicher ob der Standard vorschreibt dass das Speicherlayout eines uint32_t äquivalent zu 4 aufeinanderfolgenden uint8_t sein muss.
    (das wäre eine grössere Garantie als nur zu garantieren dass uint32_t genau 32 und uint8_t genau 8 bit gross sind.)
    Falls diese Garantie aber gilt sollte Endianess keine Probleme bereiten, da Du ja genau bestimmst was wo hinkommt.



  • Ja genau, ich hab ein int32_t Array (also in der aufrufenden Funktion), das gefüllt werden muss. Und ich missbrauche wie beschrieben 😃 Bei Arrays habe ich ja Kontrolle darüber wie das Speicherlayout aussieht.
    Ich hatte mir sorgen gemacht, dass der Cast das ganze zerstört, weil int-objekte eben von Endianess "befallen" sind. Aber wenn Casts daran nichts ändern bin ich guter Dinge.



  • Es wäre sinnvoller, du übergibst einfach die Anfangsadresse von einem char-Buffer.

    Portabel ohne Nachdenken.



  • Thez schrieb:

    Am Ende füg ich das '\0' Byte hinzu, geb nen char* auf das Objekt zurück und alles ist gut.

    Naivling.
    Du gibst vor, dir um Portabilität Gedanken zu machen und produzierst durch diesen beschriebenen Anfängerschrott schon mal selbst UB (Zugriff auf undefinierten Speicher nach deinem "Array").
    Dein Rumgecaste ist ebenso UB (wegen type punning pointer dereference).
    Der Missbrauch von uint32_t als char[4] ist schlimmstes Pfuscher-JW Niveau.



  • Wutz schrieb:

    ...

    Nun beruhig dich mal wieder. Kein Grund beleidigend zu werden.
    Er hat von Anfang an von Hausaufgabe geredet. Da stell ich keine Anforderungen wie and Production Code.
    Dein erster Einwand ist unberechtigt wenn er den letzten Punkt mit '\0' *ersetzt* (das interpretier ich mal so), dann belibt er noch innerhalb seiner Grnezen:
    Er hat dann '2','5','5','.','2','5','5','.','2','5','5','.','2','5','5','\0' = 16 Bytes im Speicher von einem int32_t[4] liegen. Das passt gerade.
    Bzgl type punning cast geht es ja gerade hauptsächlich in der Frage. Was ist hier genau UB?



  • Dein Beitrag ist sinnfrei.
    Wenn du keine Ahnung hast, unterlasse einfach deine Beiträge hier.
    Sie tragen nichts zum Thema bei und stiften nur Verwirrung.



  • Da habe ich mich ja schnell unbeliebt gemacht. Aber gegen Anfänger sag ich auch garnichts.

    Das '\0' Byte ersetzt einen der Punkte, also noch in dem Stackobjekt.
    Ich geb zu, dass das Ganze nicht annährend elegant ist.

    Aber ich merke schon, portability scheint ein großes Wort zu sein dass ich lieber nicht einfach so in den Mund nehme.

    Dann beschränke ich mich darauf: Kann ich davon aus gehen, dass der cast Grundsätzlich nichts am Speicherlayout verändert?

    Edit: Ist es mit Unions vllt. besser?



  • Das hättest du wohl gern, dass ein Zeigercast auch gleich das strict aliasing sicherstellt. Kannste vergessen, das macht kein Compiler.
    Ein Zeigercast ändert auch nicht explizit die Bitrepräsentation seines Wertes (der Adresse), außer das passiert implizit falls die beiden unterschiedliche Bytegrößen haben.

    Mit union kann man das strict aliasing break beim pointer type punning aufheben, das heißt aber nicht, dass das auch Anfänger wie du so machen sollten.

    Merke dir einfach: keine Zeigercasts, denn das ist was für Profis - genau wie die gesamte Sprache C.



  • Für die selben Profis, die gets in die stdlib gesteckt haben 🙄



  • Für dieselben Leute die dieselben getrennt schreiben, also Sachen benutzen, von denen sie keine Ahnung haben.

    Du hast auch von der C-Historie keine Ahnung, posaunst aber trotzdem dein Halbwissen durch die Gegend.

    Für deinen beschränkten Horizont:
    Ritchie hat C erfunden, und zwar für sich und sein damaliges Projekt (UNIX) inkl. sein Team. Die hatten alle Ahnung vom Programmieren. Ritchie hat C und die Bibliothek bestimmt nicht so gestaltet, dass auch 40 Jahre später noch jeder Depp - so wie du - unfallfrei die Sprache benutzen kann und sich aufregt, wenn etwas nicht laientauglich benutzbar und intuitiv bedienbar ist.



  • @Wutz
    warum bist du so unfreundlich? Keiner zwingt dich hier zu antworten. Du kommst in deinem Umfeld bestimmt gut an mit deiner Klugscheisserei. Ich les hier im Forum eigentlich ganz gerne um etwas übers programmieren zu lernen. Bei dir lernt man lediglich wie schlechtes Benehmen auf andere wirkt.



  • Ja heult mir doch allesamt nen Fluss!


Log in to reply