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:
// 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(inti=0;i<900;i++)
10
{
11
if(frameBuffer[i]<0)frameBuffer[i]=0;// <- die böse Zeile
12
elseframeBuffer[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
müsstest du nicht auch dafür unsignedFrameBuffer verwenden?
if (unsignedFrameBuffer [i] < 0) unsignedFrameBuffer [i] = 0; //
<- die böse Zeile
else unsignedFrameBuffer [i] *=2;
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!
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.
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.
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)
@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
>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
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/
@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
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 :-)
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
typedefcharint8_t;
3
typedefunsignedcharuint8_t;
Sinngemäß will ich das hier erreichen (Unter x86_64-linux-gnu mit gcc
version 4.3.2 (Debian 4.3.2-1) klappts):
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?
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.
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.
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"???
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.
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.
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.
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.
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
typedefcharint8_t;
2
typedefunsignedcharuint8_t;
3
4
intmain()
5
{
6
uint8_tunsignedFrameBuffer[900];
7
int8_t*frameBuffer=(int8_t*)unsignedFrameBuffer;
8
9
if(frameBuffer[0]<0)// hier muss es in die Hose gegangen sein
10
11
return1;
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.
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...
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.
@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.
SOLVEDSOLVEDSOLVED
Danke an alle die sich hier die Mühe mit mir gemacht haben!
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.