Compiler Bug oder 1001 C-Integer Promotion Rule?

OP #3230378
Lesenswert?
• ▲
▼
Hallo,

folgender Code läuft nicht wie erwartet. Es ist ein Fragment für eine 
kleine Menusteuerung. Hier soll einfach ein Index in einem Bereich über 
einen Drehgeber verstellt werden und ein Über/Unterlauf erfolgen.
1
int8_t read_encooder(void);
2

3
int8_t letter, encoder;
4

5
...
6

7
encoder = read_encoder();
8

9
...
10
            letter += encoder;
11
            if (letter > (sizeof(file_letters)-1) ) {
12
                letter =0;
13
            } else if (letter < 0 ) {
14
                letter = sizeof(file_letters)-1;
15
            }
16
            menu_dir[menu_letter_pos] = pgm_read_byte(&file_letters[letter]);

Wenn man es so macht, funktioniert der Unterlauf über 0 nicht. Der 
Vergleich brcs ist falsch!
1
            letter += encoder;
2
    7166:  80 91 4b 04   lds  r24, 0x044B
3
    716a:  8e 0d         add  r24, r14
4
    716c:  80 93 4b 04   sts  0x044B, r24
5
            if (letter > (sizeof(file_letters)-1) ) {
6
    7170:  88 32         cpi  r24, 0x28  ; 40
7
    7172:  18 f0         brcs  .+6        ; 0x717a <menu_fsm+0x86>
8
                letter =0;
9
    7174:  10 92 4b 04   sts  0x044B, r1
10
    7178:  05 c0         rjmp  .+10       ; 0x7184 <menu_fsm+0x90>
11
            } else if (letter < 0 ) {
12
    717a:  87 ff         sbrs  r24, 7
13
    717c:  03 c0         rjmp  .+6        ; 0x7184 <menu_fsm+0x90>
14
                letter = sizeof(file_letters)-1;
15
    717e:  87 e2         ldi  r24, 0x27  ; 39
16
    7180:  80 93 4b 04   sts  0x044B, r24
17
            }

Macht man aber einen Cast, funktioniert es! Der Vergleich brlt ist hier 
korrekt!

1
int8_t read_encooder(void);
2

3
int8_t letter, encoder;
4
...
5

6
encoder = read_encoder();
7

8
...
9
            letter += encoder;
10
            if (letter > (int8_t)(sizeof(file_letters)-1) ) {
11
                letter =0;
12
            } else if (letter < 0 ) {
13
                letter = sizeof(file_letters)-1;
14
            }
15
            menu_dir[menu_letter_pos] = pgm_read_byte(&file_letters[letter]);
1
           letter += encoder;
2
    7166:  80 91 4b 04   lds  r24, 0x044B
3
    716a:  8e 0d         add  r24, r14
4
    716c:  80 93 4b 04   sts  0x044B, r24
5
            if (letter > (int8_t)(sizeof(file_letters)-1) ) {
6
    7170:  88 32         cpi  r24, 0x28  ; 40
7
    7172:  1c f0         brlt  .+6        ; 0x717a <menu_fsm+0x86>
8
                letter =0;
9
    7174:  10 92 4b 04   sts  0x044B, r1
10
    7178:  05 c0         rjmp  .+10       ; 0x7184 <menu_fsm+0x90>
11
            } else if (letter < 0 ) {
12
    717a:  87 ff         sbrs  r24, 7
13
    717c:  03 c0         rjmp  .+6        ; 0x7184 <menu_fsm+0x90>
14
                letter = sizeof(file_letters)-1;
15
    717e:  87 e2         ldi  r24, 0x27  ; 39
16
    7180:  80 93 4b 04   sts  0x044B, r24
17
            }

Alle beteiligten Datentypen sind int8_t. Sizeof liefert int?

Was ist hier faul?

MfG
Falk
Persönliche Seite #3230399
Lesenswert?
• ▲
▼
Und hier ein Testfall für alle :-)
1
#include <stdint.h>
2

3
int b[14];
4

5
int8_t f (int8_t a)
6
{
7
    if (a > sizeof (b) -1)
8
        return a+1;
9
    return a -1 ;
10
}

Der Vergleich wird unsigned ausgeführt weil die rechte Seite unsigned 
ist.  Compilerwarnung beachten!
1
foo.c: In function 'f':
2
foo.c:6:11: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
3
     if (a > sizeof (b) -1)
4
           ^

sizeof liefert ein size_t, gemäß ABI ein "unsigned int".
Persönliche Seite #3230441
Lesenswert?
• ▲
▼
Falk Brunner schrieb:
> @ Johann L. (gjlayde) Benutzerseite
>
>>Der Vergleich wird unsigned ausgeführt weil die rechte Seite unsigned
>>ist.  Compilerwarnung beachten!
>
> Bei mir gibt es keine Warnung, -Wall ist aktiv.

Erstens ist dein Compilerversion geheim, und zweitens fehlt ein -W.

Falls -Wsign-compare noch nicht einzug in die Warning-Defaults deiner 
Version gefunden hat, setz es eben explizit. Und bei deinem Glück am 
besten gleich -Werror=sign-compare.
OP #3230680
Lesenswert?
• ▲
▼
@Johann L. (gjlayde) Benutzerseite

>> Bei mir gibt es keine Warnung, -Wall ist aktiv.

>Erstens ist dein Compilerversion geheim, und zweitens fehlt ein -W.

Ist der letzte offizielle WinAVR von 2010 mit avr-gcc 4.3.3.

>Falls -Wsign-compare noch nicht einzug in die Warning-Defaults deiner
>Version gefunden hat, setz es eben explizit. Und bei deinem Glück am
>besten gleich -Werror=sign-compare.

Aha, da spuckt er gleich einen error aus. OK, vielen Dank. Damit wäre 
das geklärt.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.