Forum: Mikrocontroller und Digitale Elektronik was macht itoa


von Gottaquest (Gast)


Lesenswert?

Ich habe hier schon einen Beitrag zu itoa gefunden, der nach dem Zweck 
fragte, bin daraus jedoch nicht schlau geworden.
[c]int b=6;
char str[100];
printf("b binaer: %s\n", itoa(b, str, 2))[c]
ich habe verstanden dass 2 bzw 16 angibt, ob die Zahl im binär bzw. 
hexadezimalsystem angegeben wird. b ist die zahl, die in 
binärschreibweise angegeben wird. Wozu brauch ich jetzt str(also einen 
char array?)

von c.m. (Gast)


Lesenswert?

google schon wieder kaputt?

lmgtfy
http://www.cplusplus.com/reference/cstdlib/itoa/

von Carl D. (jcw2)


Lesenswert?

Gottaquest schrieb:
> Ich habe hier schon einen Beitrag zu itoa gefunden, der nach dem Zweck
> fragte, bin daraus jedoch nicht schlau geworden.
> [c]int b=6;
> char str[100];
> printf("b binaer: %s\n", itoa(b, str, 2))[c]
> ich habe verstanden dass 2 bzw 16 angibt, ob die Zahl im binär bzw.
> hexadezimalsystem angegeben wird. b ist die zahl, die in
> binärschreibweise angegeben wird. Wozu brauch ich jetzt str(also einen
> char array?)

Irgendwohin muß itoa sein Ergebnis schreiben und printf möchte an der 
übergebenen Adresse einen String finden.

von Theor (Gast)


Lesenswert?

Der Parameter str, sagt der Funktion itoa, wo im Speicher es den von ihr 
erzeugten String von Ziffern ablegen soll.

Das scheint auf den ersten Blick redundant, da ja itoa als Rückgabewert, 
genau diesen Zeiger zurückgibt.

Es gibt dafür mehrere Argumente, von denen nicht alle zwingend sind.
Nur ein Beispiel:
Oft ist es so, dass Ausgabebuffer ohnehin mehrere verschiedene Daten aus 
verschiedenen Verarbeitungsschritten beinhalten. In dem man den Zeiger 
übergibt, erspart man sich z.B. das spätere Umkopieren des Ergebnisses 
und den zusätzlichen Speicher. Das trifft in Deiner Anwendung zwar nicht 
zu, aber die Funktion kann so auch für den anderen Fall verwendet 
werden.

von Marek N. (Gast)


Lesenswert?


von Carl D. (jcw2)


Lesenswert?

Hex kann printf übrigens selbst per "%x", Oktal auch per "%o", nur binär 
geht nur per Klimmzug.

: Bearbeitet durch User
von Teo D. (teoderix)


Lesenswert?

Ich such bei solch Fragen das zugehörige File raus un versuch schlau 
draus zu werden.
1
char *
2
itoa(char * buf, int val, int base)
3
{
4
  char *  cp = buf;
5
6
  if(val < 0) {
7
    *buf++ = '-';
8
    val = -val;
9
  }
10
  utoa(buf, val, base);
11
  return cp;
12
}
13
char *
14
utoa(char * buf, unsigned val, int base)
15
{
16
  unsigned  v;
17
  char    c;
18
19
  v = val;
20
  do {
21
    v /= base;
22
    buf++;
23
  } while(v != 0);
24
  *buf-- = 0;
25
  do {
26
    c = val % base;
27
    val /= base;
28
    if(c >= 10)
29
      c += 'A'-'0'-10;
30
    c += '0';
31
    *buf-- = c;
32
  } while(val != 0);
33
  return ++buf;
34
}

von Nop (Gast)


Lesenswert?

Teo D. schrieb:
1
  if(val < 0) {
2
    *buf++ = '-';
3
    val = -val;
4
  }

Dazu wäre noch anzumerken, daß diese Routine scheitert für den Wert 
INT_MIN, der nämlich keinen positiven Gegenwert hat. Sofern man diesen 
Wert niemals hat, ist die Funktion OK, aber für eine generische 
Library-Funktion sollte da ein expliziter Check drinstehen.

von Gottaquest (Gast)


Lesenswert?

Danke c.m. für den link(englischsprachige Ergebnisse sind halt wenn man 
noch am anfang ist teilweise schwer zu verstehen), Theor und den anderen 
für die Antworten.

von Teo D. (teoderix)


Lesenswert?

Nop schrieb:
> Dazu wäre noch anzumerken, daß diese Routine scheitert für den Wert
> INT_MIN, der nämlich keinen positiven Gegenwert hat.

???


PS: Das ist der original Code von xc8 (gcc Clone).

von Nop (Gast)


Lesenswert?

Teo D. schrieb:
> ???

Guck Dir mal die Wertebereiche von Integern an. Im Falle von z.B. 16 bit 
gehen die von -32768 bis 32767. +32768 ist nicht darstellbar. Also was 
passiert, wenn man der Routine -32768 übergibt und sie versucht, das 
Vorzeichen zu wechseln?

> PS: Das ist der original Code von xc8 (gcc Clone).

Der Code ist halt an der Stelle fehlerhaft.

von Carl D. (jcw2)


Lesenswert?

Teo D. schrieb:
> Nop schrieb:
>> Dazu wäre noch anzumerken, daß diese Routine scheitert für den Wert
>> INT_MIN, der nämlich keinen positiven Gegenwert hat.
>
> ???
>
>
> PS: Das ist der original Code von xc8 (gcc Clone).
Das ist dann die mit xc8 mitgelieferte Libc.

von Teo D. (teoderix)


Lesenswert?

Nop schrieb:
> Guck Dir mal die Wertebereiche von Integern an

Ja, bin Heute nich so fit. Klar hätte ich das sehen müssen, Danke.

Nop schrieb:
> Der Code ist halt an der Stelle fehlerhaft.

Gut zu wissen, ein Hobby-Programmierer sucht da wohl zuletzt. :(
(OK, der Fehler wäre schnell aufgefallen, wird aber sicher nicht der 
einzige sein)

von Carl D. (jcw2)


Lesenswert?

Teo D. schrieb:
> Nop schrieb:
>> Guck Dir mal die Wertebereiche von Integern an
>
> Ja, bin Heute nich so fit. Klar hätte ich das sehen müssen, Danke.
>
> Nop schrieb:
>> Der Code ist halt an der Stelle fehlerhaft.
>
> Gut zu wissen, ein Hobby-Programmierer sucht da wohl zuletzt. :(
> (OK, der Fehler wäre schnell aufgefallen, wird aber sicher nicht der
> einzige sein)

Es gibt diverse Hinweise im Netz zu diesem Problem INT_MIN von itoa, was 
vielleicht auch der Grund ist, warum es nicht zum C-Standard gehört. 
Oder umgekehrt.

https://en.m.wikibooks.org/wiki/C_Programming/stdlib.h/itoa

von Teo D. (teoderix)


Lesenswert?

Carl D. schrieb:
> Es gibt diverse Hinweise im Netz zu diesem Problem INT_MIN von itoa, was
> vielleicht auch der Grund ist, warum es nicht zum C-Standard gehört.
> Oder umgekehrt.

Mir war ja nicht mal bewusst, das es nicht zum C-Standard gehört 
(Obwohl es klar ist, sonnt wäre es ja nicht im Manuel vom xc8 
beschrieben).
Obwohl mir langsam dämmert, da war doch was..? :)

Nicht mal im Manual zum xc8 steht was dazu.
Ist wohl Standard das dies Jeder weiß. :´(

von Karl (Gast)


Lesenswert?

Nop schrieb:
> Guck Dir mal die Wertebereiche von Integern an. Im Falle von z.B. 16 bit
> gehen die von -32768 bis 32767. +32768 ist nicht darstellbar. Also was
> passiert, wenn man der Routine -32768 übergibt und sie versucht, das
> Vorzeichen zu wechseln?

Naja doch, eigentlich würde das gehen.

Aus -32768 ($8000) wird wieder -32768($8000). Das wird in utoa auf ein 
unsigned int gecastet und wird damit zu 32768, welches korrekt im 
Wertebereich bis 65536 liegt.

Dumm nur, wenn der Compiler das automatisch an den Wertebereich der CPU 
anpasst und aus dem $8000 bei Übergabe ein $FFFF8000 wird.

von c.m. (Gast)


Lesenswert?

Gottaquest schrieb:
> Danke c.m. für den link(englischsprachige Ergebnisse sind halt
> wenn man
> noch am anfang ist teilweise schwer zu verstehen), ...

gute englischkenntnisse sind vorauszusetzen. 2018 und so.

von Teo D. (teoderix)


Lesenswert?

Karl schrieb:
> Naja doch, eigentlich würde das gehen.

Oh man.... mir is doch schon schwindlig. Ich schau Morgen erst wieder 
hier rein. :)

von Carl D. (jcw2)


Lesenswert?

Karl schrieb:
> Nop schrieb:
>> Guck Dir mal die Wertebereiche von Integern an. Im Falle von z.B. 16 bit
>> gehen die von -32768 bis 32767. +32768 ist nicht darstellbar. Also was
>> passiert, wenn man der Routine -32768 übergibt und sie versucht, das
>> Vorzeichen zu wechseln?
>
> Naja doch, eigentlich würde das gehen.
>
> Aus -32768 ($8000) wird wieder -32768($8000). Das wird in utoa auf ein
> unsigned int gecastet und wird damit zu 32768, welches korrekt im
> Wertebereich bis 65536 liegt.
>
> Dumm nur, wenn der Compiler das automatisch an den Wertebereich der CPU
> anpasst und aus dem $8000 bei Übergabe ein $FFFF8000 wird.
Wenn [unsigned] int 32 Bit lang ist, dann existiert das Problem für 
-32768 gar nicht.
Und ja, andere Sprachen haben solche Probleme nicht, Java z.B. 
verzichtet auf unsigned und braucht dann eben immer die nächstgrössere 
Integer-Variante. Ab 64-Bit wird's dann eng, denn long long trägt dann 
den Namen BigInt mit jeder Menge Overhead.

von A. S. (Gast)


Lesenswert?

Nop schrieb:
> Dazu wäre noch anzumerken, daß diese Routine scheitert für den Wert
> INT_MIN, der nämlich keinen positiven Gegenwert hat.

Das steht doch im Kontext zum utoa - Aufruf. Bei 
2er-komplement-maschinen gibt's ja keinen Fehler. Bei den mit Vorzeichen 
auch nicht.

Wo schlägt sowas in der Praxis fehl? Also auf welchen Architekturen?

von Karl (Gast)


Lesenswert?

Carl D. schrieb:
> Java z.B.
> verzichtet auf unsigned und braucht dann eben immer die nächstgrössere
> Integer-Variante.

Da wirds aber lustig, wenn ich einen 64bit-Integer durch 10 teilen will, 
um ihn in Dezimalstellen zu zerlegen.

Sämtliche mir bekannten - ok, ich kenne sicher nicht alle - 
Ganzzahl-Divisionen erledigen signed Division dadurch, dass sie die 
negativen Zahlen negieren und dann eine unsigned Division durchführen.

von Nop (Gast)


Lesenswert?

Karl schrieb:

> Aus -32768 ($8000) wird wieder -32768($8000).

Das ist signed integer overflow und damit undefined behaviour.


Carl D. schrieb:
> Wenn [unsigned] int 32 Bit lang ist, dann existiert das Problem für
> -32768 gar nicht.

Dann existiert es in derselben Form aber für INT_MIN/32.


Achim S. schrieb:
> Wo schlägt sowas in der Praxis fehl? Also auf welchen Architekturen?

Undefined behaviour kann einen nach jedem Compiler-Update beißen. Auf 
jeder Architektur. Das ist umso schlimmer, wenn es vorher lief und sich 
um eigentlich reifgetesteten Code handelt.

von Karl (Gast)


Lesenswert?

Nop schrieb:
> Das ist signed integer overflow und damit undefined behaviour.

Ja stimmt, aber andererseits: Für 99.999% der Fälle irrelevant. Denn 
wenn ich reale Werte speichere, wird ein Integer seltenst komplett 
ausgereizt.

Dafür schleppe ich dann für den unwahrscheinlichen Fall, dass jemand 
wirklich mal mit einem Wert von -32,768m rechnet und den in ein unsigned 
Int packt immer die Prüfabfrage mit rum.

Mein Compiler mahnt auch immer an: int16 = uint16 + int16 könnte den 
Wertebereich überschreiben. Da ich weiss, dass die Werte reinpassen 
juckt mich das nicht.

Das ist bei Ada schön, da kann man festlegen: Die Zahl kommt nur 
zwischen -4000 und 12000 vor, und schon weiss der Compiler: Passt.

von Carl D. (jcw2)


Lesenswert?

Nop schrieb:
> Karl schrieb:
>
>> Aus -32768 ($8000) wird wieder -32768($8000).
>
> Das ist signed integer overflow und damit undefined behaviour.
>
>
> Carl D. schrieb:
>> Wenn [unsigned] int 32 Bit lang ist, dann existiert das Problem für
>> -32768 gar nicht.
>
> Dann existiert es in derselben Form aber für INT_MIN/32.

Hä?
Ich dachte immer NOP braucht nur Zeit, aber rechnet zu mindest nichts 
falsch.

von Nop (Gast)


Lesenswert?

Carl D. schrieb:

> Ich dachte immer NOP braucht nur Zeit, aber rechnet zu mindest nichts
> falsch.

Ist auch der Fall. INT_MIN/32 = -2147483648, und damit ist es doch 
dieselbe Konstellation wie -32768 für int/16.


Karl schrieb:
> Dafür schleppe ich dann für den unwahrscheinlichen Fall, dass jemand
> wirklich mal mit einem Wert von -32,768m rechnet und den in ein unsigned
> Int packt immer die Prüfabfrage mit rum.

Die Prüfabfrage ist doch verschwindend gering. Aber wenn man eine 
Library macht, die nicht für eine konkrete Anwendung ist, in der man die 
Wertebereiche kennt, dann sollte man das halt auch richtig machen.

Daß ausgerechnet das zum Flaschenhals in der Performance wird, halte ich 
für ausgeschlossen. Und wenn doch, dann ist die Applikation 
wahrscheinlich falsch entworfen und enthält tonnenweise Jojo-Code.

von mh (Gast)


Lesenswert?

Bevor hier weiter über evtl. vorhandene Fehler in der Library und 
fiktive 32bit Integer geschrieben wird, sollte jemand nachschauen was 
die xc8 Dokumentation zu der itoa Funktion sagt. Ich konnte in den 
letzten 5 Minuten keine Informationen finden, war aber auch nicht bereit 
den xc8 zu installieren. Ich vermute, itoa wird nirgendwo beschrieben 
und ist damit nicht zur Benutzung vorgesehen. Damit wäre jede Diskussion 
über den geposteten Quelltext überflüssig.

von Carl D. (jcw2)


Lesenswert?

Nop schrieb:
> Carl D. schrieb:
>
>> Ich dachte immer NOP braucht nur Zeit, aber rechnet zu mindest nichts
>> falsch.
>
> Ist auch der Fall. INT_MIN/32 = -2147483648, und damit ist es doch
> dieselbe Konstellation wie -32768 für int/16.

Auf einer 32-Bit-Maschine ist INT_Min/32 != INT_Min.
Es sei denn wir Programmieren in "netmask".
In C jedenfalls ist Arithmetik anders definiert.

von Nop (Gast)


Lesenswert?

Carl D. schrieb:

> Auf einer 32-Bit-Maschine ist INT_Min/32 != INT_Min.

Das war auch nicht als Arithmetik gedacht, sondern als "INT_MIN für den 
Fall eines vorzeichenbehafteten 32bit-Integers". Ich war so frei, dieses 
Ausmaß an eigenständigem Mitdenken einfach mal vorauszusetzen.

von Carl D. (jcw2)


Lesenswert?

Nop schrieb:
> Carl D. schrieb:
>
>> Auf einer 32-Bit-Maschine ist INT_Min/32 != INT_Min.
>
> Das war auch nicht als Arithmetik gedacht, sondern als "INT_MIN für den
> Fall eines vorzeichenbehafteten 32bit-Integers". Ich war so frei, dieses
> Ausmaß an eigenständigem Mitdenken einfach mal vorauszusetzen.

Dann schreib halt auch INT32_MIN

von Karl (Gast)


Lesenswert?

Nop schrieb:
> Die Prüfabfrage ist doch verschwindend gering. Aber wenn man eine
> Library macht, die nicht für eine konkrete Anwendung ist, in der man die
> Wertebereiche kennt, dann sollte man das halt auch richtig machen.

Und was ist in dem Fall richtig?

Ich hatte letztens den Fall: Division durch Null.

Normalerweise liefert die Assembler-Division dann einfach den 
Eingangswert wieder zurück. Was mathematisch nicht korrekt ist, aber 
abgefangen werden kann.

Nun hat der Compiler sich entschieden, da eine 32-bit-Division aus einer 
Lib einzubauen. Die liefert dann bei Division durch Null eine Exception. 
Was auch korrekt ist.

Dummerweise lief das auf einem µC, der natürlich keine Exception 
ausgibt. Also wurde der µC in eine Endlosschleife geschickt. Das ist 
jetzt nicht das, was man auf einem µc möchte.

von A. S. (Gast)


Lesenswert?

Karl schrieb:
> Ja stimmt, aber andererseits: Für 99.999% der Fälle irrelevant. Denn
> wenn ich reale Werte speichere, wird ein Integer seltenst komplett
> ausgereizt.

Das ist sehr gefährlich und verhindert auch nur einigermaßen 
professionellen Code.

Ich habe nichts dagegen, wenn jemand ein int i mit i++ überlaufen lässt, 
solange er
- das für seinen Compiler und Environment prüft, dass dies ohne WW3 
starten nach INT_MIN überläuft
- sich dessen bewusst ist
- das angibt, falls andere es nutzen
- exemplarisch entsprechende Asserts zur Compilezeit oder hier zur 
Laufzeit einbaut.

Das Problem fängt ja bei free-running-counter als Timer an, die weder in 
signed noch in unsigned sinnvoll, einfach und sicher nutzbar sind, es 
sei denn, man verlässt sich auf das vorliegende 2-er-Komplement.

Das Argument aber, dass es in 99.999% der Fälle gut geht, hat meist ein 
paar 9en zuviel. Sowohl das frei laufende i von oben, als auch der 
16-bit-ADC oder der 32-Bit Speicherwert laufen viel schneller in ein 
800xx als Du denkst.

von Nop (Gast)


Lesenswert?

Karl schrieb:

> Und was ist in dem Fall richtig?

Das Einfachste ist, man fragt hartcodiert auf INT_MIN ab und gibt für 
den Fall der Gleichheit ebenfalls hartcodiert den entsprechenden String 
zurück. Simpel, häßlich und zuverlässig.

Man sollte dann noch ein Compile-Time-Assert davorsetzen, daß INT_MIN 
auch tatsächlich das ist, was man glaubt, das es ist. Ein einfaches 
#ifdef mit #error tut's.

Wenn das von der Codegröße her bedenklich ist, dann ist es erst recht 
bedenklich, eine Libraryfunktion zu nutzen, die die Konvertierung zu 
diversen verschiedenen Basen beherrscht - denn das wird in diesem Umfang 
so gut wie nie gebraucht.

> Normalerweise liefert die Assembler-Division dann einfach den
> Eingangswert wieder zurück.

Je nach Controller, manche mögen es so und andere so. Manchmal kommt 
auch ein Interrupt oder Hardfault oder sowas. Deswegen validiere ich vor 
einer Division erstmal die Werte, und wenn eine Division durch 0 
anstünde, wird die Messung oder was auch immer dahintersteht als 
ungültig verworfen. Sowas kann insbesondere bei Zeitstempeln schnell mal 
passieren.

von Teo D. (teoderix)


Lesenswert?

mh schrieb:
> sollte jemand nachschauen was
> die xc8 Dokumentation zu der itoa Funktion sagt. Ich konnte in den
> letzten 5 Minuten keine Informationen finden, war aber auch nicht bereit
> den xc8 zu installieren.
1
ITOA
2
Synopsis
3
#include <stdlib.h>
4
char * itoa (char * buf, int val, int base)
5
Description
6
The function itoa converts the contents of val into a string which is stored into buf.
7
The conversion is performed according to the radix specified in base. buf is assumed
8
to reference a buffer which has sufficient space allocated to it.
9
Example
10
#include <stdlib.h>
11
#include <stdio.h>
12
void
13
main (void) {
14
  char buf[10];
15
  itoa(buf, 1234, 16);
16
  printf("The buffer holds %s\n", buf);
17
}
18
See Also
19
strtol(), utoa(), ltoa(), ultoa()
20
Return Value
21
This routine returns a copy of the buffer into which the result is written.
https://www.google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&cad=rja&uact=8&ved=0ahUKEwi93LXfmZfaAhUIXCwKHZnDC84QFggyMAE&url=http%3A%2F%2Fww1.microchip.com%2Fdownloads%2Fen%2FDeviceDoc%2F52053A.pdf&usg=AOvVaw1H4Iv0FWWapC8DB0TcCh7B

: Bearbeitet durch User
von Karl (Gast)


Lesenswert?

Nop schrieb:
> Das Einfachste ist, man fragt hartcodiert auf INT_MIN ab und gibt für
> den Fall der Gleichheit ebenfalls hartcodiert den entsprechenden String
> zurück. Simpel, häßlich und zuverlässig.

Ja aber was will ich denn auf einem µC mit einem String. Bei itoa mag 
das noch angehen, aber bei einem div / Null nützt mir das gar nichts.

von Nop (Gast)


Lesenswert?

Karl schrieb:

> Ja aber was will ich denn auf einem µC mit einem String.

Meßwerte oder so in einen String umzuwandeln, um das auf einem 
angeschlossenen Display anzuzeigen, ist ja durchaus üblich.

> aber bei einem div / Null nützt mir das gar nichts.

Doch, denn bei einer Division durch Variablen kann man sich Gedanken 
machen, wie es zustandekommen kann, daß im Nenner eine 0 steht. Das kann 
man abfangen und im einfachsten Fall die Messung für ungültig erklären.

Beispielsweise wenn man irgendeine zeitbezogene Größe berechnet und der 
Timertick sich nicht verändert hat, denn sowas kommt gerne vor, wenn ein 
Vorgang schneller als erwartet ist. Insbesondere, wenn der Vorgang 
selber auch noch parametriert ist und man daher nicht garantieren kann, 
daß er immer ausreichend lange dauert.

Schlußfolgerung: Meßdauer zu kurz. Entweder Messung verwerfen oder mit 
längerer Dauer nochmal versuchen.

Oder bei irgendwelchen Winkeln, wenn man z.B. einen Tangens braucht. 
Wenn der Winkel zu nahe an 90° ist, teilt man ebenfalls durch 0. 
Schlußfolgerung: Betrieb außerhalb des beabsichtigten Bereiches, und 
auch darauf kann man reagieren.

von Karl (Gast)


Lesenswert?

Nop schrieb:
> Doch, denn bei einer Division durch Variablen kann man sich Gedanken
> machen, wie es zustandekommen kann, daß im Nenner eine 0 steht.

Eine Division bekommt zwei Integer-Werte und gibt einen Integer zurück. 
Wie und wohin willst Du da einen String mit einem Fehler schreiben?

Sinnvoll wäre vielleicht, ein NaN zurückzugeben. Bei einem Projekt habe 
ich mal -32768 als Ganzzahl-NaN definiert, um damit ungültige Messwerte 
zu kennzeichnen. Das funktioniert aber schon nichtmehr, wenn man dann 
uint16 hat. Ist also auch nicht allgemein anwendbar.

von Nop (Gast)


Lesenswert?

Karl schrieb:

> Eine Division bekommt zwei Integer-Werte und gibt einen Integer zurück.
> Wie und wohin willst Du da einen String mit einem Fehler schreiben?

Gar nicht, ebensowenig wie bei itoa mit -32768 ein String mit einem 
Fehler geschrieben würde, sondern "-32768" als korrekter Ergebnis-String 
zurückgegeben.

Bei einer Division habe ich doch beschrieben, wie man das lösen kann. 
Grundsätzlich, indem man Eingabedaten bzw. Meßwerte vor der Verwendung 
in Berechnungen erstmal validiert. Denn das kann ja nur entweder an 
ungültigen Eingabedaten liegen, die man abfängt - oder alternativ 
natürlich an einem Fehler im Algorithmus, den man behebt.

von A. S. (Gast)


Lesenswert?

Nop schrieb:
> Das Einfachste ist, man fragt hartcodiert auf INT_MIN ab und gibt für
> den Fall der Gleichheit ebenfalls hartcodiert den entsprechenden String
> zurück. Simpel, häßlich und zuverlässig.

Wieso hartcodiert? Zu welcher Basis? Du meinst sicher: Man ruft 
hartcodiert utoa mit -INT_MIN auf, oder?

(wobei ich nicht wüsste, wie man das korrekt, portabel und defined 
macht)

von Nop (Gast)


Lesenswert?

Achim S. schrieb:

> Wieso hartcodiert? Zu welcher Basis?

Ich habe signed ints noch nie zu irgendwas anderen als Basis 10 in 
Strings konvertiert, und besonders nicht embedded. Aber Dein Vorschlag 
...

> Man ruft hartcodiert utoa mit -INT_MIN auf, oder?

... ist natürlich noch besser.

> (wobei ich nicht wüsste, wie man das korrekt, portabel und defined
> macht)

Wieso nicht? -INT_MIN wird ja zur Compilezeit ausgewertet und steht als 
Konstante da.

von Rolf M. (rmagnus)


Lesenswert?

Nop schrieb:
>> (wobei ich nicht wüsste, wie man das korrekt, portabel und defined
>> macht)
>
> Wieso nicht? -INT_MIN wird ja zur Compilezeit ausgewertet und steht als
> Konstante da.

-INT_MIN ist das gleiche wie INT_MIN!

von Nop (Gast)


Lesenswert?

Rolf M. schrieb:

> -INT_MIN ist das gleiche wie INT_MIN!

In einen signed int schon, zumindest bei Repräsentation im 
Zweierkomplement, aber doch nicht, wenn man das als Konstante zur 
Compilezeit an einen unsigned zuweist?!

von Rolf M. (rmagnus)


Lesenswert?

Nop schrieb:
> Rolf M. schrieb:
>
>> -INT_MIN ist das gleiche wie INT_MIN!
>
> In einen signed int schon,

INT_MIN ist signed.

> zumindest bei Repräsentation im Zweierkomplement,

Ja, das hatte ich jetzt nicht extra dazu geschrieben.

> aber doch nicht, wenn man das als Konstante zur Compilezeit an einen
> unsigned zuweist?!

Wohin du das Ergebnis nachher zuweist, spielt keine Rolle. Ob du INT_MIN 
oder -INT_MIN schreibst, macht keinerlei Unterschied auf einer 
Zweierkomplement-Maschine.

von Nop (Gast)


Lesenswert?

OK, gerade mal testhalber ausprobiert: also es geht, allerdings kommt 
beim Compilieren die GCC-Warnung "Ganzzahlüberlauf in Ausdruck":
1
unsigned a = -INT_MIN;
Selbes, wenn man das so macht:
1
unsigned a = INT_MAX + 1;

So herum geht das ohne Warnung, allerdings verläßt sich das aufs 
Zweierkomplement:
1
unsigned a = INT_MIN;

Das hier geht auch ohne Zweierkomplement:
1
unsigned a = INT_MAX + 1U;

von Rolf M. (rmagnus)


Lesenswert?

Nop schrieb:
> OK, gerade mal testhalber ausprobiert: also es geht, allerdings kommt
> beim Compilieren die GCC-Warnung "Ganzzahlüberlauf in Ausdruck":
>
> unsigned a = -INT_MIN;

Ja. Das Problem ist, dass in ISO C das Überlaufverhalten von 
vorzeichenbehafteten Integern nicht definiert ist. Es wird eben erst 
INT_MIN vorzeichenbehaftet negiert, und dann erst nach unsigned 
konvertiert.

> Selbes, wenn man das so macht:
> unsigned a = INT_MAX + 1;

Ja, gleiches Problem. Man könnte (unsigned)INT_MAX + 1 draus machen, 
dann würde es passen.

> So herum geht das ohne Warnung, allerdings verläßt sich das aufs
> Zweierkomplement:
> unsigned a = INT_MIN;

Das ganze hat ja auch nur im Zweierkomplement überhaupt einen Sinn. In 
Einerkomplement oder Sign/Magnitude ist der postive und negative 
Wertebereich gleich groß, und andere Arten, vorzeichenbehaftete Werte zu 
repräsentieren, lässt C nicht zu.

> Das hier geht auch ohne Zweierkomplement:
> unsigned a = INT_MAX + 1U;

Ja, damit wird die Addition unsigned durchgeführt, und dazu muss vorher 
INT_MAX ach unsigned konvertiert werden. Ist also im Prinzip äquivalent 
zu dem, was ich oben geschrieben hab.

von A. S. (Gast)


Lesenswert?

Naja, wenn man -INT_MIN zur Compile-Zeit macht, ändert das sicher kaum 
was am UB. Und alles andere ist m.E. übler, als sich (begründet, gprüft) 
darauf zu verlassen, dass einer- oder zweier-Komplement verwendet und 
angewandt wird.

von Nop (Gast)


Lesenswert?

Achim S. schrieb:
> Naja, wenn man -INT_MIN zur Compile-Zeit macht, ändert das sicher
> kaum was am UB.

Jepp, ich hatte nicht auf dem Schirm, daß auch der Compiler bei den 
statischen Ausdrücken keine Promotion macht.

> Und alles andere ist m.E. übler, als sich (begründet, gprüft)
> darauf zu verlassen, dass einer- oder zweier-Komplement verwendet und
> angewandt wird.

Prüfen kann man das ja leicht zur Compilezeit mit #ifs. Wenn 
Zweierkomplement, dann muß gelten -(INT_MIN + 1) == INT_MAX. Dann kann 
man beim hartcodierten Aufruf für den Fall INT_MIN einfach INT_MAX + 1U 
verwenden, ansonsten mit #error den denkbar unwahrscheinlichen Fall von 
Nicht-Zweierkomplement abfangen.

von Rolf M. (rmagnus)


Lesenswert?

Nop schrieb:
> Dann kann man beim hartcodierten Aufruf für den Fall INT_MIN einfach
> INT_MAX + 1U verwenden, ansonsten mit #error den denkbar
> unwahrscheinlichen Fall von Nicht-Zweierkomplement abfangen.

Oder auch einfach nichts tun. Denn schließlich ergibt sich das Problem 
wie gesagt nur bei Zweierkomplement.

von Nop (Gast)


Lesenswert?

Rolf M. schrieb:

> Oder auch einfach nichts tun. Denn schließlich ergibt sich das Problem
> wie gesagt nur bei Zweierkomplement.

Dann ist es aber wieder zur Laufzeit undefined behaviour, was man auch 
nicht gerne in einer Lib haben will.

von Rolf M. (rmagnus)


Lesenswert?

Hä? Verstehe ich nicht. Das undefined behavior gibt es wie schon gesagt 
nur beim Zweierkomplement. Also muss ich nur dann was dagegen tun.
Ob nun Zweierkomplement oder nicht, das ändert sich ja in der Regel 
während der Laufzeit nicht.

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Rolf M. schrieb:
> Hä? Verstehe ich nicht. Das undefined behavior gibt es wie schon
> gesagt nur beim Zweierkomplement. Also muss ich nur dann was dagegen tun.

Ah, ich hatte Dein "einfach nichts tun" mißverstanden als "gar nichts 
tun", während es sich tatsächlich nur auf den "ansonsten"-Fall eines 
Postings bezog.

von Nop (Gast)


Lesenswert?

Nop schrieb:
> eines Postings bezog.

_m_eines Postings.

von Rolf M. (rmagnus)


Lesenswert?

Ja genau, ich meinte "gar nichts" anstelle des "#error".

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.