Forum: Compiler & IDEs gcc 4.3.3: böse Falle bei Nicht-ASCII-Zeichen


von Harald P. (haraldp)


Lesenswert?

GCC legt ein merkwürdiges Verhalten an den Tag, wenn es um 
Nicht-ASCII-Zeichen bei Zuweisung auf uint8_t geht. Im folgenden 
Testprogramm wird die Abfrage "if (Zeich=='§') .." komplett ignoriert, 
ohne eine Warnung auszugeben.
GCC 4.1.2 (WinAVR-20070525) gibt hier wenigstens eine Warnung aus:
../Test.c:14: warning: comparison is always false due to limited range 
of data type
trotzdem ist das Verhalten nicht befriedigend, denn in beiden Versionen 
wird das "§"-Zeichen als einfaches 0xA7 codiert.
Codebeispiel:

#include <string.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/pgmspace.h>

prog_char Zeichen[] = {'#','§','+'};
uint8_t Zeich;

int main(void)
{
 Zeich = PORTB;

 if (Zeich=='#') Zeich = 1;
 if (Zeich=='§') Zeich = 1;
 PORTC = '§';
 return Zeich;
}

Ausschnitt aus Makefile
PROJECT = Test
MCU = atmega168
TARGET = Test.elf
CC = avr-gcc.exe

## Options common to compile, link and assembly rules
COMMON = -mmcu=$(MCU)

## Compile options common for all C compilation units.
CFLAGS = $(COMMON)
CFLAGS += -Wall -gdwarf-2 -std=gnu99  -DF_CPU=18432000UL -Os
##CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct 
-fshort-enums
##CFLAGS += -fno-inline -mcall-prologues -Wno-main
##CFLAGS += -fno-inline -Wno-main
##CFLAGS += -fno-inline-small-functions

ausschnitt aus lss-File:
00000068 <Zeichen>:
  68:  23 a7 2b 00                                         #.+.

..
00000094 <main>:
prog_char Zeichen[] = {'#','§','+'};
uint8_t Zeich;

int main(void)
{
 Zeich = PORTB;
  94:  85 b1         in  r24, 0x05  ; 5
  96:  80 93 00 01   sts  0x0100, r24  ; -> Zeich

 if (Zeich=='#') Zeich = 1;
  9a:  83 32         cpi  r24, 0x23  ; 35
  9c:  19 f4         brne  .+6        ; 0xa4 <main+0x10>
  9e:  81 e0         ldi  r24, 0x01  ; 1
  a0:  80 93 00 01   sts  0x0100, r24  ; -> Zeich
 if (Zeich=='§') Zeich = 1;
 PORTC = '§';
  a4:  87 ea         ldi  r24, 0xA7  ; 167
  a6:  88 b9         out  0x08, r24  ; 8
 return Zeich;
}
  a8:  80 91 00 01   lds  r24, 0x0100  ; -> Zeich
  ac:  90 e0         ldi  r25, 0x00  ; 0
  ae:  08 95         ret

000000b0 <_exit>:
  b0:  f8 94         cli

000000b2 <__stop_program>:

Harald

von Bernhard R. (barnyhh)


Lesenswert?

Mache Dich bitte mit den Feinheiten von signed und unsigned vertraut; 
dann verstehdt Du, was in Deiner Logik fehlerhaft ist.

Bernhard

von Karl H. (kbuchegg)


Lesenswert?

Bernhard R. schrieb:
> Mache Dich bitte mit den Feinheiten von signed und unsigned vertraut;
> dann verstehdt Du, was in Deiner Logik fehlerhaft ist.

@Harald

und ganz wichtig: mit den Feinheiten der int-Promotion Regel.
Die Details dazu müsstest du in deinem C-Buch finden.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

1
int foo (unsigned char x)
2
{
3
    return x == '§';
4
}
avr-gcc foo.s -S -Wextra
1
zeich.c: In function 'foo':
2
zeich.c:4:5: warning: comparison is always false due to limited range of data type [-Wtype-limits]
Die Warnung muss man aktivieren, sonst bekommt man sie natürlich 
nicht...

Das Zeichen ist ein char und damit vorzeichenbehaftet, im vorliegenden 
Falle also negativ — es sei denn, du magst -funsigned-char.

Ich sehe nur die "böse" Falle nicht. Aber die schlimmsten Fallen sind ja 
die, die man sich selber gräbt ;-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.