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.
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
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?
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.
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 ..
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.
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?
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.
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.
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.
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.
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.
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");
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
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:
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 :-)
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
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/functions/fgetc.html
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.
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
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.
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:
1
if((char)(unsignedchar)c=='Ä')
Bei mir klappt das mit default-Einstellungen aber sowieso nicht, weil
ich dann UTF-8 habe und 'Ä' deshalb aus mehreren Zeichen besteht.
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:
1
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.
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.