mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik int8_t als uint8_t interpretieren


Autor: Chris Feller (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
int8_t frameBuffer[900];
uint8_t * unsignedFrameBuffer = (uint8_t *) frameBuffer;

// Array über unsignedFrameBuffer vorzeichenfrei füllen, ich habe nur Werte bis 127! 
// Diese Werte sollen später per CAN übertragen werden.
// Für eine Filterfunktion ist es nun zwingend notwendig, auch negative Werte speichern zu können.
[...]
// Problem kommt nun:
for (int i = 0; i < 900; i++)
{
  if (frameBuffer[i] < 0) frameBuffer[i] = 0;   // <- die böse Zeile
  else frameBuffer[i] *=2;
}

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

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Chris Feller (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Karl-heinz Strunk (cletus)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl-heinz Strunk (cletus)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Hmm... (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hmm... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag:

Der GCC auf meinem System gibt folgendes aus:

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

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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/

Autor: Chris Feller (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Chris Feller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den kompletten Code wird kompliziert, sind 20-30 Quellen ;-)

Die Fehlermeldung ist in meinen Augen zwar falsch, aber nachvollziehbar:
if (frameBuffer[i] < 0)
// -> *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.
// Auszug aus types.h die verwendet wird
typedef char                  int8_t;
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):
#include <stdio.h>

int main ()
{

  unsigned char unsignedFrameBuffer[900];
  char * frameBuffer = (char *) unsignedFrameBuffer;

  unsignedFrameBuffer[0] = 255;
  unsignedFrameBuffer[1] = 10;
  frameBuffer[2] = -1;
  frameBuffer[3] = -10;
  int i;
  
  for (i = 0; i < 4; i++)
  {
    printf ("signed: %d \t unsigned: %d\n", frameBuffer[i], unsignedFrameBuffer[i]);
  }
    
  return 1;
}
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?

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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
char * frameBuffer = ...;
if (frameBuffer[i] < 0)
// -> *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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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"???

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Chris Feller wrote:

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

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.
typedef signed char    int8_t;

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johannes M. (johnny-m)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Chris Feller (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)
typedef char                  int8_t;
typedef unsigned char         uint8_t;

int main ()
{
  uint8_t unsignedFrameBuffer[900];
  int8_t * frameBuffer = (int8_t *) unsignedFrameBuffer;
   
  if (frameBuffer[0] < 0) // hier muss es in die Hose gegangen sein

  return 1;
}

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.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Johannes M. (johnny-m)
Datum:

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

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Chris Feller wrote:
>
> typedef char                  int8_t;
> 
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.

Autor: Chris Feller (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Chris Feller (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.