-
        

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 15

Thema: -1 ist großer als 3 ?

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

    -1 ist großer als 3 ?

    Anzeige

    ich habe eine merkwürdige Erscheinung

    Mein Hauptprogramm verzweigt in den "if" Zweig und mir ist eigentlich nicht klar warum. Ich weis wie ich den Fehler beheben kann, möchte aber gern verstehen warum ich das tun muss.
    wenn ich die Abfrage wie folgt ändere geht es:

    if (index >= (int)(sizeof(menue) / sizeof(TMenuStruct)))

    ich muss also eine explizite Typenwandlung vornehmen.
    Ich dachte ohne spezielle Angaben wird immer ein int angenommen...


    Code:
    typedef struct
    {
      int a;
      int b;
    } TMenuStruct;
    
    
    const TMenuStruct menue[]={
      { 1,1 },
      { 2,2 },
      { 3,3 }
    };
    
    int index;
    
    int main(void)
    {
      
      index = -1;
      if (index >= (sizeof(menue) / sizeof(TMenuStruct)))
        index = 0;
    }
    Antwort erbeten,
    mfg. Siro

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    30.05.2006
    Ort
    Pfalz
    Beiträge
    154
    Ich vermute das das die Lösung bringt:

    if (index >= (int)(sizeof(menue) / sizeof(TMenuStruct)))

    index ist vom Typ int und sizeof meines Wissens ein unsigned int oder char.
    D.h. der Vergleich könnte als unsigned ausgeführt werden.

    Bei einem 16-Bit int wird -1 Dezimal intern als 1111111111111111 Binär dargestellt.
    Wird dieser Wert in einen signed umgewandelt kommt ein Wert von 65535 raus.

    Babbage

  3. #3
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Ich dachte ohne spezielle Angaben wird immer ein int angenommen...
    Nö. Der Typ der rechten Seite ergibt sich aus den Typen der Operanden. Und da der Rückgabetyp von sizeof unsigned ist, ...
    MfG
    Stefan

  4. #4
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    521
    Den Ausdruck
    (sizeof(menue) / sizeof(TMenuStruct))
    kann der Preprozessor doch vorausberechnen und entsprechend eine Konstante einsetzen, in diesem Falle die 3. Wenn ich das selbst direkt im Programcode mache geht es auch einwandfrei.
    Warum sollte er meine index Variable plötzlich als unsigned betrachten ???? Das gibt doch irgendwie (für mich) keinen Sinn.
    Das heisst für mich soviel, daß man keinen signed mit einem unsigned korrekt vergleichen kann ohne explizite Typwandlung....
    also dann auf Nummer sicher:
    if ((int)(index) >= (int)((int)(sizeof(menue) / (int)sizeof(TMenuStruct))))
    geht doch

  5. #5
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    kann der Preprozessor doch vorausberechnen und entsprechend eine Konstante einsetzen, in diesem Falle die 3
    Nein, der Präprozessor berechnet keine Ausdrücke. Der Compiler macht das, aber selbstverständlich verändert er bei dem Ersetzen durch eine Konstante den Typ nicht. Und da sizeof einen unsigned Rückgabe-Typ hat, ist auch das Ergebnis der Division (und damit die rechte Seite des Vergleichs) ein unsigned Typ. Es ist völlig unerheblich, ob diese Division nun tatsächlich zur Laufzeit stattfindet, oder ob der Compiler dort direkt eine Konstante verwendet. Der Typ ist in beiden Fällen der gleiche.
    Wenn ich das selbst direkt im Programcode mache geht es auch einwandfrei.
    In dem Fall hat die 3 aber auch einen signed Typ.

    Das heisst für mich soviel, daß man keinen signed mit einem unsigned korrekt vergleichen kann ohne explizite Typwandlung....
    So kann man das auch wieder nicht verallgemeinern. Die Größe der Typen spielt auch noch eine Rolle. In diesem Fall würde der Vergleich zum Beispiel funktionieren:
    signed long a = -1;
    unsigned int b = 3;
    if (a < b) ...
    MfG
    Stefan

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    30.05.2006
    Ort
    Pfalz
    Beiträge
    154
    Zitat Zitat von Siro
    Warum sollte er meine index Variable plötzlich als unsigned betrachten ???? Das gibt doch irgendwie (für mich) keinen Sinn.
    Der Vergleich von einem signed und unsigned muss halt irgendwie gemacht werden.
    Wie soll der Compiler dann -1 und 3 Vergleichen wenn er nur 16 Bit hat?
    - er wandelt den int in unsigned int, dann knallt es bei negativen Werten im signed int
    - oder er wandelt den unsigned int in einen signed um, dann knallt es bei Werten Größer 32767 im unsigned int weil das dann plötzlich negative Zahlen sind

    Wie sollte da der Compiler entscheiden?
    Bringt der Compiler denn eine Warnung?

  7. #7
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Wie sollte da der Compiler entscheiden?
    Er braucht sich eigentlich nicht zu entscheiden. Der C-Standard regelt ganz genau, was in einem solchen Fall zu tun ist. Wenn die beiden Typen die gleiche Größe haben, sich aber in der Signedness unterscheiden, "gewinnt" immer der unsigned Typ (der signed Typ wird also in den unsigned Typ gewandelt).
    MfG
    Stefan

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    30.05.2006
    Ort
    Pfalz
    Beiträge
    154
    @sternst war ne rethorische Frage nachdem diese Umwandlung für Siro keinen Sinn ergab.

  9. #9
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    521
    Ersteinmal Danke für Euer Interesse,
    sternst schrieb:

    "gewinnt" immer der unsigned Typ (der signed Typ wird also in den unsigned Typ gewandelt).

    Meine Meinung:
    Das finde ich "ABSOLUT FATAL", das muss ja schiefgehen.


    weil ich habe Jahrzehntelang Assembler programmiert
    und bin unweigerlich irgendwann auf selbiges Problem gestoßen,
    einen Signed mit einem Unsigned zu vergleichen.
    Habe mich dann dafür entschieden, sobald "ein" Signed im Spiel ist,
    beide Operatoren als Signed zu interpretieren. Die Wahrscheinlichkeit
    daß meine Werte unglücklicherweise im Bereich des "Vorzeichens" landen,
    also bei 16 Bit > 32768 oder bei 32 Bit ..... wahr eher gering.
    Wie die C-Compiler das nun auswerten, da habe ich natürlich keinen Einfluß. Ich bin nur wirklich erstaunt, daß es in meinem Beispiel schief läuft und das völlig ohne irgend ein Warning.
    Na wa solls, Wichtig ist, ich habe das Problem erkannt und kann entsprechend entgegenwirken.

    Was ich aber überhaupt nicht verstehe:
    Wie schon erwähnt ist eine Auflösung des Codes:
    sizeof(menue) / sizeof(TMenuStruct)
    eine Konstante, hier wird ja keine "Funktion" aufgerufen
    und es ist absolut sichergestllet, daß ein positiver Wert rauskommt.
    Und genau diesen Wert soll er ja einsetzten.
    Ob signed oder unsigned ist hier völlig unerheblich.
    Es ist lediglich eine "Konstante". Wie kommt er dazu meinen als
    signed definierten "index" als unsigned zu interpretieren ?

    Okay, jetzt bin ich wieder beim Text vom "sternst"
    "gewinnt" immer der unsigned Typ (der signed Typ wird also in den unsigned Typ gewandelt).

    Im nächsten Leben schreibe ich meine Compiler selber.
    Spass muss sein.

    Siro

  10. #10
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Zitat Zitat von Siro
    Habe mich dann dafür entschieden, sobald "ein" Signed im Spiel ist,
    beide Operatoren als Signed zu interpretieren.
    Nun, die Herren und Damen, die den C-Standard festsetzen, entschieden sich eben anders...

    Wie die C-Compiler das nun auswerten, da habe ich natürlich keinen Einfluß.
    Man hat aber Einfluß darauf, die C-Doku zu lesen

    Ich bin nur wirklich erstaunt, daß es in meinem Beispiel schief läuft und das völlig ohne irgend ein Warning.
    Freilich muss man Warnungen auch aktivieren und berücksichtigen. Als Optionen sind mindestend -W -Wall ratsam, und mein avr-gcc warnt die Stelle auch an.
    "foo.c:7: warning: comparison between signed and unsigned"

    Was ich aber überhaupt nicht verstehe:
    [...] es ist absolut sichergestllet, daß ein positiver Wert rauskommt.
    Und genau diesen Wert soll er ja einsetzten.
    Ob signed oder unsigned ist hier völlig unerheblich.
    Es ist lediglich eine "Konstante". Wie kommt er dazu meinen als
    signed definierten "index" als unsigned zu interpretieren?
    Der Compiler muss eben einen Vergleich ausführen, und den kann er signed oder unsigned machen. Der C-Standard ergibt, daß der Vergleich auf unsigned zu machen ist. Auf einer Maschine, wo ein int 32 Bits groß ist, könnte eine Promotion nach 32 Bits stattfinden, und das Ergebnis wäre wie von dir erwartet. Aber hier ist ein int 16 Bits groß und es wird nicht über int-Größe hinaus erweitert.

    An manchen Stellen ist der C-Standard so geschrieben daß "vernünftiger" Code gut optimierbar ist. Beispiel sind etwa die Strict-Aliasing-Rules oder die etwas seltsame EIgenschaft von Shifts: Ein wert in einer Schleife 100x um 1 nach links zu schieben gibt idR was anderes, als ein << 100.

    Im nächsten Leben schreibe ich meine Compiler selber.
    Spass muss sein.
    Dann ist der Compiler aber die falsche Baustelle für dich, zumindest wenn es ein Compiler werden soll, der sich an Standards hält. Du musst schon zur Fraktion der Standard-Schreiber wechseln
    Disclaimer: none. Sue me.

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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