int8_t als uint8_t interpretieren

Gast #1116678
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
Gast #1117017
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!
#1117052
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.
Gast #1117150
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
Persönliche Seite #1117238
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/
Gast #1117553
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
#1117560
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 :-)
Gast #1117626
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?
Gast #1117633
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.
#1117636
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.
#1117646
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.
#1117647
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;
Gast #1117656
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.
#1117675
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.
Gast #1117690
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.
Gast #1117699
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...
#1117703
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.
Gast #1117779
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!

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