-         

Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 24

Thema: explizite Typumwandlung

  1. #1
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    525

    explizite Typumwandlung

    Anzeige

    Guten Morgen,
    ich habe eine, oder sind es mehrere Fragen zur Typumwandlung. Zunächst ganz einfach:

    Code:
    Warum funktioniert folgender Code nicht wie erhofft ?
    
    int* p = (char*)1000;   /* p zeigt nun auf die Speicherstelle 1000 */
    (char*)p++;
    
    p zeigt nun auf 1004 leider nicht wie erwartet auf 1001. Das "Casten" wurde anscheinend völlig ignoriert ?
    
    und das Folgende meckert der Compiler komplett an:
    void* p = (void*)1000;  
    
    (char*)p++;   /* expression must be a pointer to a complete object type */
    
    
    Erklärung was ich machen möchte:
    Eine universelle Funktion schreiben, der ich lediglich eine Adresse und eine Anzahl übergebe um Daten mittels RS232 zu übertragen.
    VOID möchte ich benutzen, damit ich später keine explizite Typwandlung mehr benötige. Also einen Pointer auf irgendwas übergeben kann.
    So soll es aussehen:
    
    void uart_putc(char c)
    {
        /* ....... */
    }
    
    void uart_send(void* data, unsigned int size)
    {
       while(size--)
          uart_putc(*(char*)data++);   /* hier gibt es das Problem */
    }
    
    
    Ich war ja schon fleißig und habe natürlich schon einige Versionen ausprobiert und hinbekommen
    So geht es zum Beispiel:
    
    void uart_send(void* data, unsigned int size)
    { char*p=data;
    
       while(size--)
          uart_putc(*p++);
    }
    
    aber wozu die unnötige, lokale Zwischenvariable "p" , ich hab doch schon meinen Pointer "data" den muss ich doch Byteweise hochzählen können.
    Ich bedanke mich schon im voraus für (meinen neuen Lerneffekt) bzw. Eure Hilfe.
    Siro

  2. #2
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.836
    Versuch mal
    ( (char*)p ) ++;
    ich hab's aber nicht probiert, also ohne gewähr

    Gedanke dahinter:
    (char*)p++ heisst ja, er soll das, was bei p++ rauskommt, als char* interpretieren.

    Ich mach das meist so:
    p = (int*) ((int)p + 1);
    geht aber sicher eleganter, ich bin aber nicht an Forschung interessiert , hauptsache, es funzt
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  3. #3
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    11.12.2007
    Ort
    weit weg von nahe Bonn
    Alter
    33
    Beiträge
    2.381
    also wie PickNick und auch ich das sehen, ist das nur logisch, es wird ERST p++ ausgehführt und DANACH der cast auf char-pointer!
    PickNicks Lösung musst du verwenden, dann sollte es gehen!

    Der 2te fehler ist genau das gleiche Problem, er kann einen void-pointer nicht inkrementieren, weil der Cast erst NACH der Operation durchgeführt werden würde!

    @PickNick deine 2te Lösung sieht gruselig aus, du castest die Adresse in einen Zahlenwert um, manipulierst ihn udn dann wieder zu einem Pointer ... (da schüttelt es mich XD)

    PS: ich würde statt einem char* lieber einen byte* oder einen uint8* verwenden ... ist jetzt nur ne stilsache, aber char kann auch als unicode interpretiert werden und der hat 16bit!

    muss mich selber zusammenreissen nicht immer char zu schreiben


    Code:
    void uart_send(void* data, unsigned int size) {    
       while(size--)       
          uart_putc(*(((byte*)data)++));   /* erst casten, dann inkrementen, dann  dereferenzieren */ 
    } 
    
    void uart_send(void* data, unsigned int size, unsigned int repeat = 1 ) {    //keine Ahnung ob der WinAVR optionale Parameter unterstützt aber macht es noch multifunktionaler!
       while(repeat--) 
       {
          for(unsigned int i = 0; i < size; i++)       
             uart_putc(*(((byte*)data)++));   /* erst casten, dann inkrementen, dann  dereferenzieren */ 
       }
    }
    So viel Klammer muss halt sein wenn man sicher gehen will dass der compiler es auch versteht!
    Geändert von Ceos (06.10.2011 um 12:29 Uhr)
    Es gibt 10 Sorten von Menschen: Die einen können binär zählen, die anderen
    nicht.

  4. #4
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.836
    Wegen Grusel und Graus : Das rumcasten erzeugt ja keinen Code, sondern zwingt den Compiler zu anderen MaschinenInstruktionen. Insofern bleibt nur die schaurige Optik in der Source, da geb' ich dir schon recht.

    Mir persönlich graust mehr, wenn einer elegant die gauss'sche Osterberechnung in ein Statement quetscht
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  5. #5
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Zitat Zitat von Ceos
    PS: ich würde statt einem char* lieber einen byte* oder einen uint8* verwenden ... ist jetzt nur ne stilsache, aber char kann auch als unicode interpretiert werden und der hat 16bit!
    char ist laut Definition der kleinste Typ in C (sizeof(char) ist immer 1). Wenn ein char 16 Bit hat (was durchaus sein kann), dann gibt es in der Umgebung ein uint8_t schlicht nicht. Und auch byte (was immer das konkret sein mag) kann dann nicht kleiner als 16 Bit sein.
    MfG
    Stefan

  6. #6
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    525
    Ein bischen weiter geholfen habt Ihr mir ja, aber Eure Lösungen scheinen nicht so zu funktionieren wie ich es wollte.

    Zu PicNick:

    p = (int*) ((int)p + 1);

    erhöht bei mir den Zeiger um 4, hab ich grad mal ausprobiert.


    Zu Ceos:

    uart_putc(*(((byte*)data)++));

    gibt bei mir einen Fehler: expression must be a modifiable lvalue


    Zumindest hab ich jetzt verstanden, daß der Compiler anscheinend von rechts nach links auswertet.
    Dann leuchtet mir ein, daß mein Lösungsweg auch nicht funktionieren konnte.


    Lösung steht also noch aus......Danke Euch schonmal für die Anteilnahme

    Siro

  7. #7
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Was genau stört dich eigentlich an der Variante mit der lokalen Variable?
    Das ist eine saubere und vor allem auch gut lesbare Lösung. Und weniger effizient wird sie auch nicht sein. Würde mich wundern, wenn die zusätzliche Variable auch im Binärcode als solche auftauchen würde.
    MfG
    Stefan

  8. #8
    Erfahrener Benutzer Robotik Einstein Avatar von Felix G
    Registriert seit
    29.06.2004
    Ort
    49°32'N 8°40'E
    Alter
    34
    Beiträge
    1.780
    Ähm...
    wieso tut ihr euch das überhaupt an!?

    Pointerarithmetik ist ja schön und gut, aber in 99% aller Fälle geht es auch sehr viel bequemer:

    Code:
    void uart_send(void* data, uint16_t size)
    {
       uint16_t n;
       uint8_t* data8 = (uint8_t*)data;
    
       for(n=0; n<size; n++)
          uart_putc(data8[n]);
    }
    
    oder alternativ:
    
    void uart_send(void* data, uint16_t size)
    {
       uint16_t n;
    
       for(n=0; n<size; n++)
          uart_putc(((uint8_t*)data)[n]);
    }
    Ja, es ist eine Zählvariable dazugekommen, aber dafür ist der Code leichter lesbar und weniger fehleranfällig.
    (Außerdem wird n niemals im Speicher existieren, der Compiler verwendet einfach ein Register dafür)
    So viele Treppen und so wenig Zeit!

  9. #9
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    525
    Hallo Stefan,
    meine gefundene, oben gezeigt Lösung ist ja auch "saubere Sache" und auch "sehr gut lesbar" da stimmen wir völlig überein.
    So benutze ich es zur Zeit auch.
    Aber wenn ich mich schon in eine neue Programmiersprache reinarbeite, möchte ich auch möglichst viele Details kennen lernen.
    Deshalb kommen halt solche Fragen auf. Ich möchte immer aufs Bit genau wissen was passiert, das liegt in der jahrelangen
    Programmierung in Assembler, da stört mich jede zusätzliche Variable oder Zeile.
    Optimiert ein Compiler heutzutage auch lokale Variablen weg ?. Möglich wäre es ja. Aber das wäre sicher ein anderes Thema....

    Aber mal generell. Kann man denn überhaupt ein Variable "vorher" casten, die mit einem Postincrement/Postdecrement verarbeitet wird.
    Denn wenn ich mir die Kommenatre hier so ansehe, führt der Compiler "zuerst das "increment" durch und dann castet er.
    Wie kann ich ihm denn beibringen, dass er "erst casten" soll und dann das Postincrement. Geht das überhaupt ?
    Das ist rein zum Verständnis, ich möchte da sicher keine Wissenschaft draus machen.
    Mir ist anscheinend (ganz sicher sogar) noch nicht klar, wie der Compiler den Code interpretiert.
    Den Kommentaren nach von rechts nach links. Das kann aber so auch nicht sein,
    dann würde x=*p++; falsch laufen. Wenn er erst incrementieren würde und dann den Wert zuweist.
    Also muss er sich doch erst den Wert holen um ihn x zuzuweisen und dann darf er den pointer incrementieren.
    Wie soll man das also casten, daß sichergestellt ist, daß der pointer nur um eins incrementiert wird.

    Auch wenns nervt Ich Danke Dir
    Siro

  10. #10
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    525
    Hallo Felix G,
    Oho, das funktioniert schon mal. Hab ich gleich mal ausgetestet.
    Und ja, Du hast recht, für "n" wird ein Register verwendet, zumindest bei meinem Compilat.
    Das man einen Pointer wie ein Array benutzen kann, war mir noch nicht klar.
    Hat sich also mein Beitrag gelohnt. Ich bedanke mich.

    Der Vollständigkeit halber nochmal 4 Lösungen:

    Code:
    void uart_send(void* data, unsigned int size)
    { char *p = data;
    
      while (size--)
      {  
        uart_putc(*p++);
      }  
    } 
    
    void uart_send(void* data, unsigned int size)
    { int i;
      
      for (i=0; i< size; i++)
      {  
        uart_putc(((char*)data)[i]);
      }  
    } 
    
    void uart_send(void* data, unsigned int size)
    { 
      while (size--)
      {  
        uart_putc(*(char*)data);
        data = (char*)data+1;
      }  
    } 
    
    void uart_send(void* data, unsigned int size)
    { 
      while (size--)
      {  
        uart_putc(*(char*)data);
        ++(*((char**)(&data)));
      }  
    }
    Siro
    Geändert von Siro (07.10.2011 um 09:49 Uhr)

Seite 1 von 3 123 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •