www.mikrocontroller.net

Forum: Compiler & IDEs Atoi für Unsigned


Autor: Lars (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich verwende ein Array von unsigned char und konvertiere dieses mittels 
atoi in eine uint_16. Das gibt erst einmal eine warning, weil atoi als 
Argument ja einen Zeiger auf ein char array erwartet.
Wie kann ich denn nun möglichst elegant aus einem String ein uint16_t 
erzeugen? Ich möchte möglichst den gesamten Wertebereich ausnutzen und 
brauche nur positive Zahlen.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
strtoul()

Selbermachen ist aber auch nicht viel länger als der Aufruf davon.

Autor: 123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wenn du nur unsigned char werte 0-255 in uint_16 werte "wandeln" willst
ist atoi der total falsche ansatz

ich gehe mal davon aus das du weißt wozu atoi da ist ...

ASCII to Integer

wenn du komplette strings hast ..
sollte der string eh in einem char xx[] liegen

da sonst hier eh alle möglichen anderen funktinen meckern

Autor: Lars (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich würde das jetzt so aufrufen:

strtoul(buffer,NULL,0);

Allerdings gibt das immer noch eine Warnung:

pointer targets in passing argument 1 of 'strtoul' differ in signedness

Das liegt daran, dass buffer ein array of unsigned char ist. Aber wenn 
ich es einfach signed mache sollte es ja für meine Anwendung (ASCII) 
keinen Unterschied machen oder?

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

Bewertung
0 lesenswert
nicht lesenswert
Da du weißt, das in deinem unsigned char Array im Grunde ein String 
vorliegt, es sich also um char handelt, kannst du den Pointer auf einen 
char* zurechtcasten.
In dem Fall ist das zulässig und auch ok.

Autor: Lars (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder ich deklariere buffer gleich als array of char, oder hat das 
irgendwelche Nachteile?

Autor: 123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
erklär mal kurz was du machen willst ...
ich lese nur heraus das du eine warning bekommst wegen singed/unsigned


oben schreibst du das du ein unsigned char array mit daten .. ( was für 
daten ??  ASCII ??   0-255 ??  0x00 - 0xFF ?? ( is das selbe ..ich weiß 
)  )
in ein anderes array mit uint_16 wandeln willst

wenn du hier nichts wandeln willst sondern nur die werte in das uint_16 
array schreiben möchtest .. dann tu das ..

Autor: Lars (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe in einem array of unsigned char verschiedene Werte(ASCII). 
Dieses Array soll in eine uint_16 zahl gewandelt werden.

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

Bewertung
0 lesenswert
nicht lesenswert
Lars schrieb:
> Oder ich deklariere buffer gleich als array of char, oder hat das
> irgendwelche Nachteile?

Kommt drauf an.
Die Frage ist an dieser Stelle: Warum hast du dann überhaupt uint8_t 
genommen?


  char     für alles was mit Texten zu tun hat
  sint8_t  kleiner Integer mit 8 Bit und Vorzeichen
  uint8_t  kleiner Integer mit 8 Bit ohne Vorzeichen

so werden die Datentypen eingesetzt.

Wenn du deinen Buffer immer und überall immer nur im Sinne von "enthält 
einen Text" benutzt, gibt es keinen Grund warum der uint8_t sein muss.

Autor: 123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zur not caste dir das array beim aufruf hin


unsigned char buffer[x]

atoi( (char*) buffer , .... );

Autor: Lars (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gut das weiß ich eben auch nicht mehr, warum der uint_8 ist. Ist schon 
eine Weile her. Also in dem Array steht nur Text. Also werde ich einfach 
char nehmen.

Aber mal eine Frage am Rande. Wieso lässt Char negative Zahlen zu? ASCII 
ist doch positiv oder etwa nciht?

Autor: 123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
die frage ist wie man die daten interpretiert ...

für mich ist sowas bis auf floatwerte immer 0x00 bis 0xff
und ASCII zeichen "0"  ist eben 0x30 ....

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lars schrieb:

> Aber mal eine Frage am Rande. Wieso lässt Char negative Zahlen zu?

Weil's der Referenzcompiler so implementierte. Und der tat es dies, weil 
die Referenzmaschine PDP-11 es in Hardware so tat. C liess das zwar 
stets offen, auch damals schon, aber viele Compiler schleppen das seit 
damals mit.

> ASCII ist doch positiv oder etwa nciht?

Undefiniert. Kann sein, kann nicht sein.

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

Bewertung
0 lesenswert
nicht lesenswert
Lars schrieb:

> Aber mal eine Frage am Rande. Wieso lässt Char negative Zahlen zu?

wer sagt das?

Ob char ein Vorzeichen hat oder nicht, entscheidet der, der den Compiler 
schreibt. Der C-Standard lässt ihm das frei und oftmals kann man dem 
Compiler beim Aufruf auch noch sagen wie man es gerne hätte.

Daher auch: Will ich einen char im Sinne von 'eine Variable die einen 
kleinen Integer speichern kann' benutzen, dann nehme ich niemals char, 
sondern immer die Varianten, bei der ich explizit ein Vorzeichen 
anfordere oder eben nicht anfordere

> ASCII
> ist doch positiv oder etwa nciht?

ASCII ist in seiner ursprünglichen Pracht ein 7-Bit Code.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:

>> ASCII ist doch positiv oder etwa nciht?
>
> Undefiniert. Kann sein, kann nicht sein.

PS: ASCII ist positiv, aber 'Ä' im ISO-Zeichensatz ist nicht Bestandteil 
von ASCII und kann je nach Compiler negativ sein, wenn im "char" 
gespeichert.

Autor: Lars (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gut also mache ich das Array jetzt char. Aber wenn ich uint16 erhalten 
will muss ich trotzdem

strtoul(buffer,NULL,0);

statt

atoi(buffer);

verwenden.

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

Bewertung
0 lesenswert
nicht lesenswert
Lars schrieb:
> Gut also mache ich das Array jetzt char. Aber wenn ich uint16 erhalten
> will muss ich trotzdem
>
> strtoul(buffer,NULL,0);
>
> statt
>
> atoi(buffer);
>
> verwenden.

Ja.
es gibt kein atou und es gibt auch kein strtoui

Allerdings wäre das keine schlechte Übung für dich, dir ein strtoui bzw. 
ein atou zu machen. Vermeidet den long zwischendurch.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lars schrieb:
> Gut das weiß ich eben auch nicht mehr, warum der uint_8 ist. Ist schon
> eine Weile her. Also in dem Array steht nur Text. Also werde ich einfach
> char nehmen.
>
> Aber mal eine Frage am Rande. Wieso lässt Char negative Zahlen zu?

Die Frage stellt sich eigentlich nicht, denn mit Text rechnet man ja 
nicht. Der Compiler muß eben irgendeinen Integer-Typ als 
darunterliegenden Typ verwenden, um die Zeichen abzuspeichern. Welcher 
das ist, spielt aber eigentlich keine Rolle.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Magnus schrieb:

> Die Frage stellt sich eigentlich nicht, denn mit Text rechnet man ja
> nicht. Der Compiler muß eben irgendeinen Integer-Typ als
> darunterliegenden Typ verwenden, um die Zeichen abzuspeichern. Welcher
> das ist, spielt aber eigentlich keine Rolle.

So die Theorie. Allein die Praxis...

'Ä' sei bei "char" mit Vorzeichen beispielsweise -60. EOF ist aber 
gewohnheitsmässig -1. Die Standardfunktion getchar() gibt "int" zurück, 
um chars und EOF auseinander halten zu können. Damit getchar() aber 
nicht schon bei 0xFF Schluss macht, gibt es vor EOF nur positive Werte 
zurück, bei Ä also nicht -60, sondern 195.

Folglich wird
   int c = getchar();
   if (c == 'Ä') printf("AE");
nicht funktionieren und man muss Hand anlegen:
   if (c == ('Ä' & 0xFF)) printf("AE");
oder
   if ((char)c == 'Ä') printf("AE");

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lars schrieb:
> Aber mal eine Frage am Rande. Wieso lässt Char negative Zahlen zu? ASCII
> ist doch positiv oder etwa nciht?

Wer sagt denn, dass überhaupt ASCII verwendet werden muss? Richtig, 
niemand. ANSI C sagt dazu nur, dass eine Sammlung von bestimmten Zeichen 
in jedem Fall unterstützt werden muss, und dass diese Zeichen in einem 
char dargestellt werden können.

Wie der Compiler das macht, bleibt ihm überlassen, deshalb kann man sich 
(wenn man portabel bleiben will) nicht darauf verlassen, dass '0' 
gleich 0x30 ist. Landest du z.B. mal auf einem IBM-Grossrechner 
(EBCDIC), dann ist dort '0' gleich 0xF0, und das kann dann je nach 
Compiler auch durchaus einen negativen char-Wert ergeben.

Andreas

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> 'Ä' sei bei "char" mit Vorzeichen beispielsweise -60. EOF ist aber
> gewohnheitsmässig -1. Die Standardfunktion getchar() gibt "int" zurück,
> um chars und EOF auseinander halten zu können. Damit getchar() aber
> nicht schon bei 0xFF Schluss macht, gibt es vor EOF nur positive Werte
> zurück, bei Ä also nicht -60, sondern 195.

Nein, das ist zumindest durch den Standard so nicht erlaubt. Bei 
folgendem Code muss AFAIK der Vergleich am Ende wahr sein, wenn 'Ä' ein 
"printing character" ist und kein IO-Error auftritt:
FILE *f = fopen("test", "w+");
long int pos = ftell(f);
fputc('Ä', f);
fseek(f, pos, SEEK_SET);
int c = fgetc(f);
if (c == 'Ä')
    printf("OK\n");

Andreas

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

Bewertung
0 lesenswert
nicht lesenswert
Andreas Ferber schrieb:

> Wer sagt denn, dass überhaupt ASCII verwendet werden muss? Richtig,
> niemand. ANSI C sagt dazu nur, dass eine Sammlung von bestimmten Zeichen
> in jedem Fall unterstützt werden muss, und dass diese Zeichen in einem
> char dargestellt werden können.

Im Prinzip richtig.

Die Frage nach ASCII oder nicht ASCII ist mitlerweile mehr oder weniger 
eine rein akademsiche Frage geworden. Auch wenn natürlich niemand 
vorschreibt, dass dem so ist.

> Landest du z.B. mal auf einem IBM-Grossrechner
> (EBCDIC),

Wenn er je auf einem IBM Mainframe kommt, dann stellt sich die Frage so 
gar nicht mehr. Mit der Betonung auf 'wenn'.
Und dann ist EBCDIC sein geringstes Problem :-)

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Ferber schrieb:

> Nein, das ist zumindest durch den Standard so nicht erlaubt.

Ausprobiert?
#include <stdio.h>

int main(int argc, char **argv)
{
    FILE *f;
    int c;
    long pos;
    
    f = fopen("test", "w+");
    pos = ftell(f);
    fputc('Ä', f);
    fseek(f, pos, SEEK_SET);
    c = fgetc(f);
    printf("AE=%d c=%d\n", 'Ä', c);
    if (c == 'Ä')
        printf("OK\n");
    else
        printf("Nicht OK\n");
}

Microsoft:
AE=-60 c=196
Nicht OK

Digital Mars:
AE=-60 c=196
Nicht OK

Linux GCC:
AE=-60 c=196
Nicht OK

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Ausprobiert?

Nein. Trotzdem lag' ich nicht ganz falsch, der Hund liegt hier begraben:

[c]
#include <stdio.h>
#include <ctype.h>

int main(void)
{
        printf("isprint('AE')=%d\n", isprint('Ä'));
}
[c]

=> isprint('AE')=0

(GCC, x86, Linux)

Andreas

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Hund liegt in der Definition von fgetc begraben: "... the fgetc() 
function shall obtain the next byte as an unsigned char converted to an 
int ...". 
http://www.opengroup.org/onlinepubs/000095399/func...

Es geht auch garnicht nicht anders, aufgrund des Konflikts mit 0xFF und 
der mindestens faktischen Festlegung von EOF auf -1.

Das ist auch kein sprachtheoretisches Problem sondern eine nicht zu Ende 
gedachte Definition ebendieser fget[c|char] Funktionen.

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das wiederspricht aber IMO in bestimmten Konstellationen dann dem 
C-Standard selbst (oder der Standard ist an der Stelle lückenhaft).

Wenn man vor dem ganzen noch ein setlocale(LC_ALL, "de_DE"); macht 
(soweit das System diese Locale unterstützt natürlich), dann wird 'Ä' je 
nach System auf einmal zum Printing Character (7.4.1.8 Absatz 2):

  The isprint function tests for any printing character
  including space (' ').

Unter GCC/Linux gibt isprint('Ä') dann in der Tat einen wahren Wert 
zurück.

Nach der Definition von Text Streams müsste dann beim Zurücklesen etwas 
"equal" vergleichendes rauskommen (7.19.2 Absatz 2):

  [...] Data read in from a text stream will necessarily
  compare equal to the data that were earlier written out
  to that stream only if: the data consist only of printing
  characters and [...]

Allerdings (und das ist der Punkt, wo man den Standard als lückenhaft 
bezeichnen kann) steht AFAIK nirgendwo explizit, dass die 
stdio-Funktionen die Locale berücksichtigen, man kann das höchstens 
indirekt schliessen, da in der Beschreibung auf Locale-behaftete 
Begriffe wie "printing character" zurückgegriffen wird.

Andreas

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist völlig schnurz ob das Ä printable ist und wie die locales 
eingestellt sind, denn wenn getc() nicht unabhängig von der 
Vorzeicheneigenschaft 0..255 zurück gibt, dann lassen sich Binärfiles 
damit bei vorzeichenbehaftetem "char" nicht verarbeiten. Und sie werden 
damit verarbeitet. Diese Funktionen sind (mit "w+b") nicht nur auf 
druckbare Zeichen definiert.

Ja, das ist inkonsistent. fgetc/EOF ist defekt, ein Konstruktionsfehler. 
Das steht nur nicht dabei. Wäre EOF beispielsweise als (CHAR_MIN-1) 
definiert worden, wäre das Problem vom Tisch und fgetc() dürfte für Ä 
-60 zurück geben.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Der Hund liegt in der Definition von fgetc begraben: "... the fgetc()
> function shall obtain the next byte as an unsigned char converted to an
> int ...".

Richtig. Deshalb wäre das folgende auch falsch:

Andreas Ferber schrieb:
> FILE *f = fopen("test", "w+");
> long int pos = ftell(f);
> fputc('Ä', f);
> fseek(f, pos, SEEK_SET);
> int c = fgetc(f);
> if (c == 'Ä')
>     printf("OK\n");

Die letzte if-Abfrage müßte heißen:
if ((char)(unsigned char)c == 'Ä')

Bei mir klappt das mit default-Einstellungen aber sowieso nicht, weil 
ich dann UTF-8 habe und 'Ä' deshalb aus mehreren Zeichen besteht.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Magnus schrieb:

> Die letzte if-Abfrage müßte heißen:

So geht's auch (wie ich oben schon schrieb), der andere cast ist erstens 
redundant und zweitens in der besagten Definition von fgetc schon drin:
if ((char)c == 'Ä')

> Bei mir klappt das mit default-Einstellungen aber sowieso nicht, weil
> ich dann UTF-8 habe und 'Ä' deshalb aus mehreren Zeichen besteht.

Du darfst auch '\xC4' schreiben.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Es geht auch garnicht nicht anders, aufgrund des Konflikts mit 0xFF und
> der mindestens faktischen Festlegung von EOF auf -1.

EOF braucht man eigentlich gar nicht. Das ist eh nur eine Optimierung, 
um nicht jedesmal feof() aufrufen zu müssen.
EOF kann (zumindest theoretisch) sowieso nicht eindeutig sein, da es ja 
auch eine Plattform geben kann, wo char und int gleich groß sind. Da 
gäbe es gar keinen Wert für EOF, der nicht auch ein gültiger char-Wert 
sein könnte.

A. K. schrieb:
> der andere cast ist in der besagten Definition schon drin

Der ist eigentlich gerade nicht drin. Der Compiler liest das Byte in 
einen unsigned char und konvertiert den nach int. Mein Cast macht jetzt 
erst wieder den unsigned char draus und konvertiert den dann nach char. 
Du hast aber recht damit, daß man diesen Cast weglassen kann.

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.