Compiler Bug oder 1001 C-Integer Promotion Rule?

#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.
#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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren