Forum: Compiler & IDEs Atoi für Unsigned


von Lars (Gast)


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.

von (prx) A. K. (prx)


Lesenswert?

strtoul()

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

von 123 (Gast)


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

von Lars (Gast)


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?

von Karl H. (kbuchegg)


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.

von Lars (Gast)


Lesenswert?

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

von 123 (Gast)


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 ..

von Lars (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


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.

von 123 (Gast)


Lesenswert?

zur not caste dir das array beim aufruf hin


unsigned char buffer[x]

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

von Lars (Gast)


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?

von 123 (Gast)


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 ....

von (prx) A. K. (prx)


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.

von Karl H. (kbuchegg)


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.

von (prx) A. K. (prx)


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.

von Lars (Gast)


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.

von Karl H. (kbuchegg)


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.

von Rolf Magnus (Gast)


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.

von (prx) A. K. (prx)


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");

von Andreas F. (aferber)


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

von Andreas F. (aferber)


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:
1
FILE *f = fopen("test", "w+");
2
long int pos = ftell(f);
3
fputc('Ä', f);
4
fseek(f, pos, SEEK_SET);
5
int c = fgetc(f);
6
if (c == 'Ä')
7
    printf("OK\n");

Andreas

von Karl H. (kbuchegg)


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 :-)

von (prx) A. K. (prx)


Lesenswert?

Andreas Ferber schrieb:

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

Ausprobiert?
1
#include <stdio.h>
2
3
int main(int argc, char **argv)
4
{
5
    FILE *f;
6
    int c;
7
    long pos;
8
    
9
    f = fopen("test", "w+");
10
    pos = ftell(f);
11
    fputc('Ä', f);
12
    fseek(f, pos, SEEK_SET);
13
    c = fgetc(f);
14
    printf("AE=%d c=%d\n", 'Ä', c);
15
    if (c == 'Ä')
16
        printf("OK\n");
17
    else
18
        printf("Nicht OK\n");
19
}

Microsoft:
AE=-60 c=196
Nicht OK

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

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

von Andreas F. (aferber)


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

von (prx) A. K. (prx)


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/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.

von Andreas F. (aferber)


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

von (prx) A. K. (prx)


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.

von Rolf Magnus (Gast)


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:
1
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.

von (prx) A. K. (prx)


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:
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.

von Rolf Magnus (Gast)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.