Zeigertyp casten



  • Hi zusammen,

    ich habe folgendes Problem: in einer Funktion 'Ausgabe' soll ein Array mit Integerwerten byteweise bearbeitet werden.

    void ausgabe(uint8_t* byteArray) {
    	//byteArray bearbeiten; 
    }
    
    void funktionA() {
    	uint16_t intArray[10];
    	ausgabe(&intArray()); //so geht es nicht
    }
    

    Funktion 'Ausgabe' benötigt daher einen Zeiger auf uint8_t. Das in FunktionA erzeugte Array enthält aber Integerwerte. Frage an euch: Wie kann ich den Anfang von intArray als uint8_t-Zeiger übergeben?

    Gruß Joerg



  • Der Name eines Arrays zerfällt beim schief anschauen schon in einen Pointer auf das erste Element des Arrays:

    #include <cstdint>
    
    void ausgabe(char unsigned *byteArray)
    {}
    
    int main()
    {
        std::uint16_t intArray[10];
        ausgabe(reinterpret_cast<char unsigned*>(intArray));
    }
    


  • @joerg55 Beachte auf jeden Fall auch die Typen, die @Swordfish hier verwendet. So ein Cast (mit anschliessendem Zugriff) ist nur mit (unsigned) char und std::byte erlaubt, kurioserweise jedoch nicht mit uint8_t, sonst gibts UB. Für alle anderen Typen std::memcpy oder ab C++20 std::bit_cast.



  • @Swordfish sagte in Zeigertyp casten:

    ausgabe(reinterpret_cast<char unsigned*>(intArray));

    Dankeschön, ich habe jetzt einfach

    ausgabe(reinterpret_cast<uint8_t*>(intArray))
    

    genommen, da ich auf die Funktion 'ausgabe' keinen Einfluss habe. Das funktioniert trotz des Einwandes von @Finnegan einwandfrei. Was ist UB?



  • @joerg55 UB = undefined behaviour, es darf also funktionieren, darf aber auch deinen PC formatieren und eine Sonnenfinsternis auslösen. Es ist schlicht nicht definiert, was passiert.



  • @Schlangenmensch ,

    hm, noch ist es hell. Was wäre der korrekte Weg?



  • @joerg55 Dafür weiß ich zu wenig über dein Problem. Warum hast du ein uint_16tarray? Wenn du ein uint_16t benötigst, wie soll dann eine Funktion damit arbeiten die nur auf uint_8t ausgelegt ist? Welches Byte soll jeweils verwendet werden? Oder beide? Das musst du ja irgendwo selbst entscheiden.
    Wenn es nur um eine byteweise Ausgabe geht, kannst du, wie von @Finnegan vorgeschlagen std::memcpy verwenden (https://en.cppreference.com/w/cpp/string/byte/memcpy).



  • Das funktioniert trotz des Einwandes von @Finnegan einwandfrei. Was ist UB?

    UB ist "undefiniertes Verhalten" (undefined behavior). Es kann funktionieren, es kann aber auch irgendwas anderes tun (wie zum Beispiel gar nichts, das Programm beenden, oder irgendwelche anderen Fehler verursachen). Vor allem darf es sich auch von Compiler zu Compiler unterschiedlich verhalten - und von Version zu Version. Theoretisch sogar von Mondphase zu Mondphase. Das ist daher etwas, das man vermeiden will. Manche Implementierungen können auch garantieren, dass der Code wie gewünscht funktioniert. Jedoch erlaubt der Sprachstandard dann, dass "irgendwas" passiert.

    Das kann die Ursache für subtile Bugs sein. UB sollte man unbedingt vermeiden.

    Wenn du ein static_assert(std::is_same_v<std::uint8_t, char> || std::is_same_v<std::uint8_t, unsigned char>, ""); einbaust, sollte sich aber kein UB ergeben, weil dann sichergestellt ist, dass uint8_t ein char ist (und dann ist die Konvertierung ja erlaubt), wenn ich https://stackoverflow.com/questions/16260033/reinterpret-cast-between-char-and-stduint8-t-safe richtig verstehe. Und das ist fast immer gegeben.



  • @joerg55 sagte in Zeigertyp casten:

    @Schlangenmensch ,

    hm, noch ist es hell. Was wäre der korrekte Weg?

    Gar nicht casten, weil es das Problem der Byte-Order gibt. Man kann das nur portabel lösen, wenn man Bitshifts macht.



  • Besten Dank, euch allen. Mein Compiler zeigt

    • typedef unsigned char uint8_t,

    wenn ich den Cursor über uin8_t halte. Wenn ich euch richtig verstanden habe, muss das nicht so sein. Obwohl mein Programm nur für mich selbst ist, also nicht portabel zu sein braucht, habe ich jetzt den Vorschlag von @wob aufgegriffen und ein static_assert eingebaut. Das zeigt natürlich wegen obiger typedef keinen Fehler an.



  • @joerg55 sagte in Zeigertyp casten:

    ...
    genommen, da ich auf die Funktion 'ausgabe' keinen Einfluss habe. Das funktioniert trotz des Einwandes von @Finnegan einwandfrei. Was ist UB?

    @joerg55 sagte in Zeigertyp casten:

    ...
    ... Obwohl mein Programm nur für mich selbst ist, also nicht portabel zu sein braucht, ...

    🤔



  • Es ist prinzipiell eine sinnfreie Idee, Zeiger zu casten.
    Bitrepräsentation ist sekundär, die wesentlichen Probleme rühren vom Alignment her - und da helfen auch keine obskuren C++ Casts, das ist und bleibt UB.



  • @Wutz sagte in Zeigertyp casten:

    da helfen auch keine obskuren C++ Casts

    Schon wieder? Tu nicht so als wäre ein C-Style Cast in diesem Fall etwas anderes.

    @Wutz sagte in Zeigertyp casten:

    die wesentlichen Probleme rühren vom Alignment her

    Ja? Im Konkreten Fall?



  • Depp. Plumpe durchschaubare Unterstellung.
    Du willst es nicht verstehen oder du kannst es nicht weil du nicht lesen kannst/willst.
    Der standardisierte 4fache Stroustrup-Cast-Unsinn angewandt auf Zeiger ergibt dasselbe UB wie es mit purem C zu machen - nur eben, dass C solche "sichere-Casts" suggerierenden Unfälle nicht standardisiert.



  • @Wutz Du redest Blödsinn.


Log in to reply