Forum: Mikrocontroller und Digitale Elektronik int8_t als uint8_t interpretieren


von Chris Feller (Gast)


Lesenswert?

Hallo zusammen,

ich programmiere auf einem ARM7 und würde gerne den Inhalt eines Arrays 
(Bilddaten) je nach Kontext (versenden oder filtern) entweder als int8_t 
oder als uint8_t interpretieren. Ich dachte das müsste mit einem Pointer 
doch ganz einfach möglich sein:
1
int8_t frameBuffer[900];
2
uint8_t * unsignedFrameBuffer = (uint8_t *) frameBuffer;
3
4
// Array über unsignedFrameBuffer vorzeichenfrei füllen, ich habe nur Werte bis 127! 
5
// Diese Werte sollen später per CAN übertragen werden.
6
// Für eine Filterfunktion ist es nun zwingend notwendig, auch negative Werte speichern zu können.
7
[...]
8
// Problem kommt nun:
9
for (int i = 0; i < 900; i++)
10
{
11
  if (frameBuffer[i] < 0) frameBuffer[i] = 0;   // <- die böse Zeile
12
  else frameBuffer[i] *=2;
13
}

An dieser Stelle merkt der Compiler nun folgendes an:
*warning: comparison is always false due to limited range of data type*

Prinzipiell sollte es doch möglich sein, 2 verschiedene Sichtweisen auf 
den selben Speicherbereich zu haben. Und solange das MSB nicht gesetzt 
wird (durch große unsigned Werte) sollte das doch gehen, oder nicht?
Könnt ihr mir da bitte auf die Sprünge helfen?

Schöne Grüße
Chris

von Peter (Gast)


Lesenswert?

müsstest du nicht auch dafür unsignedFrameBuffer  verwenden?

  if (unsignedFrameBuffer  [i] < 0) unsignedFrameBuffer  [i] = 0;   // 
<- die böse Zeile
  else unsignedFrameBuffer  [i] *=2;

von holger (Gast)


Lesenswert?

>  if (frameBuffer[i] < 0) frameBuffer[i] = 0;   // <- die böse Zeile

Vieleicht hilft ein cast:

 if (frameBuffer[i] < (int8_t)0) frameBuffer[i] = 0;   // <- die böse 
Zeile

von Chris Feller (Gast)


Lesenswert?

Danke schon mal, leider hats nix gebracht.

@Peter: ich will an der Stelle doch auf kleiner 0 prüfen, daher brauch 
ich hier die signed Version.

@holger: da hilft der Cast leider nicht weiter ...

Trotzdem Danke für Mühe und Denkanstöße!

von Karl-heinz S. (cletus)


Lesenswert?

Chris Feller wrote:
> Danke schon mal, leider hats nix gebracht.
>
> @Peter: ich will an der Stelle doch auf kleiner 0 prüfen, daher brauch
> ich hier die signed Version.
>
> @holger: da hilft der Cast leider nicht weiter ...
>
> Trotzdem Danke für Mühe und Denkanstöße!

Wenn du statt u_variable[i] anders *(u_variable + i) schreibst meckern 
viele Compiler nicht  mehr... Ist aber eher unsauber.

Wenn du das öfter hin und her casten musst, kannst du dir unions 
ansehen.

von Karl-heinz S. (cletus)


Lesenswert?

Chris Feller wrote:
> @Peter: ich will an der Stelle doch auf kleiner 0 prüfen, daher brauch
> ich hier die signed Version.

Beim signed gilt: Variable ist < 0, wenn das höchstwertige Bit = 1 ist.

von Karl H. (kbuchegg)


Lesenswert?

Ich kann mir nicht helfen.
Die Fehlermeldung passt einfach nicht zur gezeigten Codestelle.
Bist du sicher, dass dir der Compiler diese Zeile anmerkt?

(Ist keine Schande, ist mir auch schon passiert, dass ich an der 
falschen Stelle nachgesehen habe)

von Hmm... (Gast)


Lesenswert?

@Karl-Heinz:

Wieso denn? Wenn frameBuffer aus 'unsigned'-Elementen besteht so sind 
diese niemals kleiner Null bzw. negativ und der Ausdruck liefert 
entsprechend immer falsch.

> if (frameBuffer[i] < 0) frameBuffer[i] = 0;   // <- die böse Zeile

von Hmm... (Gast)


Lesenswert?

Nachtrag:

Der GCC auf meinem System gibt folgendes aus:

main.c|40|Warnung: Vergleich ist durch beschränkten Wertebereich des 
Datentyps stets »unwahr«|

von holger (Gast)


Lesenswert?

>Vieleicht hilft ein cast:
> if (frameBuffer[i] < (int8_t)0) frameBuffer[i] = 0;   // <- die böse

Vieleicht so rum?

 if ((int16_t)frameBuffer[i] < 0) frameBuffer[i] = 0;   // <- die böse

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Hmm... wrote:
> Wieso denn? Wenn frameBuffer aus 'unsigned'-Elementen besteht so sind
> diese niemals kleiner Null bzw. negativ und der Ausdruck liefert
> entsprechend immer falsch.

Der Ausdruck besteht aber nicht aus 'unsigned' Elementen, sondern aus 
int8_t.
Was für GCC verwendet Ihr denn?

Mein arm-none-eabi-gcc.exe (Sourcery G++ Lite 2008q3-66) 4.3.2 gibt mir 
keine Fehlermeldung. Auch "ARM C/C++ Compiler, RVCT4.0 [Build 471]" und 
"RVCT3.1 [Build 942]" (aus Keil MDK) bersetzen das korrekt und ohne zu 
meckern.

Gruß
Marcus
http://www.doulos.com/arm/

von Chris Feller (Gast)


Lesenswert?

@cletus:
> Wenn du statt u_variable[i] anders *(u_variable + i) schreibst meckern
> viele Compiler nicht  mehr... Ist aber eher unsauber.
Liefert leider die selbe Fehlermeldung.
> Beim signed gilt: Variable ist < 0, wenn das höchstwertige Bit = 1 ist.
So einfach kann es sein ... und ich habs selber noch angedeutet ... 
Danke!
Ich denke das genügt mir schon. Allerdings ist mir das eigentliche 
Problem dahinter immer noch unklar.

@holger:
Auch dieser Cast ist leider vergeblich, ich hab so langsam aller 
Permutationen druchgecastet :-)

Ich verwende übrigens den arm-elf-gcc (GCC) 4.0.2 und ein abgewandeltes 
Keil makefile

von Karl H. (kbuchegg)


Lesenswert?

Chris Feller wrote:

> Ich denke das genügt mir schon. Allerdings ist mir das eigentliche
> Problem dahinter immer noch unklar.

Da bist du nicht alleine.
Kannst du mal den kompletten Source Code posten + Originale 
Fehlermeldung (incl Zeilennummer)

Die Fehlermeldung passt überhaupt nicht zu dem Code-Ausschnitt den du 
gezeigt hast. Es sei denn irgendjemand hat sich einen Spass gemacht und 
ein

#define int8_t unsigned char

davor gesetzt (oder einen gleichwertigen typedef). Dann gehört er aber 
mit dem nassen Fetzen erschlagen :-)

von Chris Feller (Gast)


Lesenswert?

Den kompletten Code wird kompliziert, sind 20-30 Quellen ;-)

Die Fehlermeldung ist in meinen Augen zwar falsch, aber nachvollziehbar:
1
if (frameBuffer[i] < 0)
2
// -> *warning: comparison is always false due to limited range of data type*
Hier wird die Speicherstelle wohl als unsigned interpretiert, und daher 
ist < 0 außerhalb des Wertebereichs. Eine "1" anstelle der "0" lässt die 
Meldung verschwinden. Aufgrund das Datentyps des Pointers müsste der 
Wertebereich aber -128 ... 127 sein.
1
// Auszug aus types.h die verwendet wird
2
typedef char                  int8_t;
3
typedef unsigned char         uint8_t;

Sinngemäß will ich das hier erreichen (Unter x86_64-linux-gnu mit gcc 
version 4.3.2 (Debian 4.3.2-1) klappts):
1
#include <stdio.h>
2
3
int main ()
4
{
5
6
  unsigned char unsignedFrameBuffer[900];
7
  char * frameBuffer = (char *) unsignedFrameBuffer;
8
9
  unsignedFrameBuffer[0] = 255;
10
  unsignedFrameBuffer[1] = 10;
11
  frameBuffer[2] = -1;
12
  frameBuffer[3] = -10;
13
  int i;
14
  
15
  for (i = 0; i < 4; i++)
16
  {
17
    printf ("signed: %d \t unsigned: %d\n", frameBuffer[i], unsignedFrameBuffer[i]);
18
  }
19
    
20
  return 1;
21
}
Ausgabe:
signed: 1    unsigned: 1
signed: 10   unsigned: 10
signed: -1   unsigned: 255
signed: -10  unsigned: 246

Gibt es da irgendwelche Compilerflags des arm-elf-gcc die das bewirken / 
verhindern könnten?

von Sven P. (Gast)


Lesenswert?

Ist die C-Bibliothekt evtl. kaputt?
Guck mal nach der Definition von 'uint8_t' -- wenn die nur 'char' ist, 
dann ist sie kaputt (müsste 'signed char' sein).
Ansonsten kannst du noch '-funsigned-char' als Option versuchen.

von (prx) A. K. (prx)


Lesenswert?

Wenn andere Leute mit dem Problem umgehen sollen, dann muss es 
reproduzierbar sein. D.h. du solltest eine Minimalversion zurecht 
basteln, die genau das von dir als falsch angesehene Verhalten 
produziert, nichts überflüssiges enthält und so wie geliefert 
kompilierbar ist.

Nicht kompilierbarer Quellcode nützt praktisch nichts. Denn wenn bei 
signed char dies hier wirklich so zusammengehört
1
char * frameBuffer = ...;
2
if (frameBuffer[i] < 0)
3
// -> *warning: comparison is always false due to limited range of data type*
und char nicht zufällig auf "unsigned" gesetzt ist (z.B. mit 
-funsigned-char) dann handelt es sich um einen Compilerfehler, und um 
damit umgehen zu können wird ohnehin ein minimaler Testfall benötigt. 
Mit 100KB Quellcode und 30 Quellfiles fängt niemand etwas an.

Die exakte Version des Compilers wird auch benötigt.

von (prx) A. K. (prx)


Lesenswert?

Sven Pauli wrote:

> Guck mal nach der Definition von 'uint8_t' -- wenn die nur 'char' ist,
> dann ist sie kaputt (müsste 'signed char' sein).

uint8_t als "signed char"???

von (prx) A. K. (prx)


Lesenswert?

Chris Feller wrote:

>   unsignedFrameBuffer[0] = 255;
>   unsignedFrameBuffer[1] = 10;
>   frameBuffer[2] = -1;
>   frameBuffer[3] = -10;

> signed: 1    unsigned: 1
> signed: 10   unsigned: 10
> signed: -1   unsigned: 255
> signed: -10  unsigned: 246

Du bist ganz sicher, dass hier Code und Ausgabe zusammen gehören?  Denn 
255 ist weder signed noch unsigned gleich 1.

von Karl H. (kbuchegg)


Lesenswert?

Chris Feller wrote:

>
1
// Auszug aus types.h die verwendet wird
2
> typedef char                  int8_t;
3
> typedef unsigned char         uint8_t;
4
>

Ah, da haben wir ihn ja.
Offenbar ist bei deinem Compiler der default für char ein unsigned char.
Ob du das jetzt über Commandline Switsches erzwungen hast oder nicht, 
spielt erst mal keine Rolle.

Du solltest einen Bug Report an den Entwickler dieses Compilers (oder 
wer auch immer das types.h wartet) schicken.
1
typedef signed char    int8_t;

von Sven P. (Gast)


Lesenswert?

A. K. wrote:
> Sven Pauli wrote:
>
>> Guck mal nach der Definition von 'uint8_t' -- wenn die nur 'char' ist,
>> dann ist sie kaputt (müsste 'signed char' sein).
>
> uint8_t als "signed char"???

Ja.

von Johannes M. (johnny-m)


Lesenswert?

Sven Pauli wrote:
>> uint8_t als "signed char"???
>
> Ja.
Wirklich? Warum heißt der wohl *u*int8_t?

von Karl H. (kbuchegg)


Lesenswert?

A. K. wrote:
> Karl heinz Buchegger wrote:
>
>> Offenbar ist bei deinem Compiler der default für char ein unsigned char.
>
> Dann müssten aber bei dem obigen printf() immer nur positive Zahlen
> rauskommen, denn dann würde der Compiler die Parameter immer auf int
> 0-255 erweitern. Etwas wie das gezeigte "signed: -1 unsigned: 255" wäre
> dann nicht möglich.

Was weiß ich, vielleicht hat er ja im Makefile seines Projekts die 
unsigned char Forcierung drinnen. (Habs auch grade erst gesehen. Dieses 
Beispiel stammt von einem anderen Compiler)

Aber für sein ursprüngliches Posting, mit der Fehlermeldung UND dem 
Wissen dass in types.h  ein int8_t als plain vanilla char definiert ist, 
gibt es nur eine Schlussfolgerung:
Irgendjemand zwingt den Compiler einen char als unsigned aufzufassen.
Wie und wodurch, kann ich nicht sagen. Da müsste man jetzt die komplette 
Toolchain durchforsten.

Aber wie auch immer:
In types.h hat ein typedef für int8_t der auf plain vanilla char aufbaut 
ganz sicher nichts verloren.

von Chris Feller (Gast)


Lesenswert?

Sorry für die Verwirrung. Das obige Beispiel war auf nem x86 zur 
Verdeutlichung, was ich eigentlich haben will!

Also, hier mein Minimalprogramm für den arm-elf-gcc (gcc version 4.0.2)
1
typedef char                  int8_t;
2
typedef unsigned char         uint8_t;
3
4
int main ()
5
{
6
  uint8_t unsignedFrameBuffer[900];
7
  int8_t * frameBuffer = (int8_t *) unsignedFrameBuffer;
8
   
9
  if (frameBuffer[0] < 0) // hier muss es in die Hose gegangen sein
10
11
  return 1;
12
}
Ergebnis:
$ arm-elf-gcc signednessTestARM.c
signednessTestARM.c: In function ‘main’:
signednessTestARM.c:9: warning: comparison is always false due to 
limited range of data type
Ebenso:
$ arm-elf-gcc -funsigned-char signednessTestARM.c
signednessTestARM.c: In function ‘main’:
signednessTestARM.c:9: warning: comparison is always false due to 
limited range of data type

> Irgendjemand zwingt den Compiler einen char als unsigned aufzufassen.
> Wie und wodurch, kann ich nicht sagen. Da müsste man jetzt die komplette
> Toolchain durchforsten.
> Aber wie auch immer:
> In types.h hat ein typedef für int8_t der auf plain vanilla char aufbaut
> ganz sicher nichts verloren.

klingt logisch, da werde ich mal ansetzen.

von Sven P. (Gast)


Lesenswert?

Johannes M. wrote:
> Sven Pauli wrote:
>>> uint8_t als "signed char"???
>>
>> Ja.
> Wirklich? Warum heißt der wohl *u*int8_t?
Ups.

:-) Wollte sagen: Hauptsache da steht explizit was vor dem 'char', 
dadrauf kommts an...

von Johannes M. (johnny-m)


Lesenswert?

Sven Pauli wrote:
> :-) Wollte sagen: Hauptsache da steht explizit was vor dem 'char',
> dadrauf kommts an...
Ach so, verstehe...;-)

von Johannes M. (johnny-m)


Lesenswert?

Chris Feller wrote:
>
1
> typedef char                  int8_t;
2
>
Warum machst Du da nicht einfach ein signed char draus, wie es oben 
schon beschrieben wurde? Nochmal: char ist nicht eindeutig signed oder 
unsigned ("implementation defined"). Wenn Du einen vorzeichenbehafteten 
Wert haben möchtest, dann musst Du, um von irgendwelchen anderen 
Einstellungen unabhängig zu sein, explizit signed da hinschreiben.

Und wenn das sowieso ein GCC ist, warum benutzt Du dann nich die 
stdint.h, in der die Typen alle schön sauber definiert sind? Eigene 
Typen zu definieren (die dann auch noch die selben Namen haben wie die 
Bibliothekstypen) ist Unsinn.

von Chris Feller (Gast)


Lesenswert?

@kbuchegg & johnny-m:
Volltreffer! Die Sache ist die, meine Arbeit setzt auf der meiner 
Vorgänger auf, und ich hab die types.h heute zum ersten mal wirklich 
angeschaut. Nach einfügen des von signed gibts kein Gemecker vom 
Compiler mehr. Daher geh ich mal davon aus, dass die Werte jetzt korrekt 
gespeichert werden.

SOLVED
SOLVED
SOLVED

Danke an alle die sich hier die Mühe mit mir gemacht haben!

von Chris Feller (Gast)


Lesenswert?

Ach ja,

ich hatte die Idee mit dem signed das erste mal überlesen, weil ich 
für mein Antwort-Posting ne Weile gebraucht hatte. Ich hab es dann 
nimmer gelesen, weils ja drüber steht.

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.