Hi,
ich habe zwei Variablen, nicht vorzeichenbehaftet:
uint8_t a=0, b=0; //können werte von 0-255 enthalten.
Ich möchte b von a abziehen und auf das Ergebnis "reagieren"
if ((a-b)>=0)
{
dies
}
else
{
das
}
Wenn a kleiner b ist, dann wäre das Ergebnis ja negativ und damit
kleiner Null. Wird das hierbei berücksichtigt oder muss ich noch irgenwo
"casten"?
Wenn das so nicht geht, würde das dann gehen?
if ((int16_t(a-b))>=0)
Oder müsste ich es so machen?
if ( ( (int16_t a)-(int16_t b) ) >=0 )
Danke
Gruß
TS
Thorsten S. schrieb:> Wenn a kleiner b ist, dann wäre das Ergebnis ja negativ und damit> kleiner Null.
Wenn du unsigned Datentypen verwendest, gibt es keine negativen
Ergebnisse.
2 - 3 = 255
Die Berechnung wird natürlich ohne Probleme durchgeführt.
Wenn das Ergebnis negativ sein würde, wird das wieder auf Positive
Zahlen abgebildet.
Bei 8-Bit Variablen bist du dann Mathematisch ausgedrückt in einem
"Endlicher Körper" von 2^8=256. Es gibt nur Zahlen zwischen 0 und 255.
Das Ergebnis wird automatisch Modulo 256 gerechnet.
Beispiel:
11 - 42 = -31 => -31 Mod 256 = 225
Wolfgang schrieb:> Wenn du unsigned Datentypen verwendest, gibt es keine negativen> Ergebnisse.> 2 - 3 = 255
Ich dachte das wäre aus meinen Ansätzen mit dem Type Cast zu einem
sigend Typ klar.
EAF schrieb:> if((((int16_t)a)-((int16_t)b))>=0)
Danke.
Hannes J. schrieb:> Einfach nicht voneinander abziehen oder erst nach dem Vergleich> abziehen:
Genial, manchmal hat man einen Knoten im Hirn...
Gruß
TS
Thorsten S. schrieb:> Wolfgang schrieb:>> Wenn du unsigned Datentypen verwendest, gibt es keine negativen>> Ergebnisse.>> 2 - 3 = 255>> Ich dachte das wäre aus meinen Ansätzen mit dem Type Cast zu einem> sigend Typ klar.
Nur weil du mit (int16_t(a-b)) aus den bspw. 255 ein signed machst, wird
das im Nachhinein nicht negativ.
Warum rechnest du die Differenz aus, wenn du wissen willst, ob a>=b ist?
Thorsten S. schrieb:> uint8_t a=0, b=0; //können werte von 0-255 enthalten.> if ((a-b)>=0)> Wenn a kleiner b ist, dann wäre das Ergebnis ja negativ und damit> kleiner Null. Wird das hierbei berücksichtigt oder muss ich noch irgenwo> "casten"?
Was heißt "berücksichtigt"?
Auf Grund der Integer Promotion werden a und b erst mal nach (signed)
int konvertiert, bevor die Rechnung ausgeführt wird. Das passiert in C
grundsätzlich mit allem, was kleiner ist als int. Das Ergebnis kann also
sehr wohl negativ sein.
Rolf M. schrieb:> Auf Grund der Integer Promotion
Bullshit. Wenn sowohl a als auch b vom Typ uint8_t sind [1] dann
wird für die Rechnung (a-b) gar nichts promoted. Für den Vergleich mit
dem int Literal 0 würde ein Compiler vielleicht promoten. Aber da
liegt das Kind ja bereits im Brunnen.
Und ein vernünftiger Compiler (jeder?) würde erkennen, daß ein uint8_t
(bzw jeder unsigned) immer >= 0 ist. Er würde also den ganzen Vergleich
wegoptimieren und eine Warnung ausspucken.
[1] wohl unsigned char auf allen nicht-exotischen Platformen
Axel S. schrieb:> Bullshit. Wenn sowohl a als auch b vom Typ uint8_t sind [1] dann> wird für die Rechnung (a-b) gar nichts promoted.
Lern die Sprache, bevor du so einen Unsinn von dir gibst. Die Promotion
findet statt!
Bei
uint8_t a=0, b=0;
entspricht die Rechnung
(a - b)
aufgrund der Promotion Regeln dem Ausdruck
((int)a - (int)b)
weil, simpel ausgedrückt, alles kleiner als int als int gerechnet wird
und int definitiv grösser als uint8_t ist. Anders wärs bei
unsigned a=0, b=0;
weil a und b dabei nicht kleiner als int sind.
Axel S. schrieb:> Wenn sowohl a als auch b vom Typ uint8_t sind [1] dann wird für> die Rechnung (a-b) gar nichts promoted.
Das ist kompletter …
> Bullshit.> Und ein vernünftiger Compiler (jeder?) würde erkennen, daß ein uint8_t> (bzw jeder unsigned) immer >= 0 ist. Er würde also den ganzen Vergleich> wegoptimieren und eine Warnung ausspucken.
Auch das ist …
> Bullshit.
Axel S. schrieb:> Bullshit. Wenn sowohl a als auch b vom Typ uint8_t sind [1] dann> wird für die Rechnung (a-b) gar nichts promoted. Für den Vergleich mit> dem int Literal 0 würde ein Compiler vielleicht promoten. Aber da> liegt das Kind ja bereits im Brunnen.>> Und ein vernünftiger Compiler (jeder?) würde erkennen, daß ein uint8_t> (bzw jeder unsigned) immer >= 0 ist. Er würde also den ganzen Vergleich> wegoptimieren und eine Warnung ausspucken.
Du irrst
Avr gnu++c17 -Os
Um das zu verstehen muss man wissen, dass der C-Compiler
unterschiedliche Algorithmen (Rechen-Methoden) für unterschiedliche
Datentypen anwendet.
Wenn die Operanden alle "unsinged int" sind, verwendet er einen
Algorithmus der nur damit funktioniert und auch nur ein solches Ergebnis
liefern kann.
Subtraktionen können falsche Ergebnisse liefern, wenn der Wertebereich
des Ergebnisses überschritten wird. In diesem Fall eben bei negativen
Zahlen.
Bei Additionen und Multiplikationen können Überläufe stattfinden.
"unsigned int" ist normalerweise 16 Bit. Wenn du 20000·40 berechnest,
hast du so einen Überlauf. Es sei denn, du vastest wenigstens einen
Operand auf "long int". Dann wird nämlich der größere Algorithmus für 32
Bit verwendet.
Bei Divisionen on Integer Zahlen werden keine Nachkomma-Stellen
berechnet, weil der Algorithmus das nicht kann. Ist hingegen einer der
Operanden eine Fließkommazahl, dann wird der komplexere Algorithmus
verwendet, der Nachkomma-Stellen im Ergebnis liefert.
Zusätzlich muss natürlich das Ergebnis in eine dazu passende Variable
geschrieben werden, sonst wird es nochmal umgewandelt, was eventuell mit
Verlusten behaftet ist.
> int8_t ergebnis = 3.0 * 5.0;
Das ist OK, weil das Ergebnis 15 ist und in die Variable passt.
> int8_t ergebnis = -3.0 * 5.0;
Das ist nicht OK, weil die Variable keine Negativen Zahlen speichern
kann. Das Resultat wird fehlerhaft sein.
Inden meisten Programmiersprachen (auch C, allerdings nicht auf AVR) ist
die Division durch 0 die einzige ungültige Operation, die zu einem
Programmabbruch führt. Alle anderen ungültigen Kombinationen führen
lediglich zu kaputten Ergebnissen, das Programm läuft aber trotzdem
weiter.
Wahrscheinlich gibt es noch mehr Ausnahmen, aber so habe ich es mir
gemerkt.
Stefan ⛄ F. schrieb:> "unsigned int" ist normalerweise 16 Bit
Das hat noch nicht einmal in jeder Zeit gestimmt, um die es in der
Retro-Diskussion im Nachbarthread geht. Stimmen tut nur: es ist
mindestens 16 Bit breit. Und so selten sind 32-Bitter auch in
Mikrocontrollern nicht.
Oliver S. schrieb:> Trink erst mal einen Kaffee, boote anständig durch, und dann schreibste> das nochmal. Ohne all den Quatsch.
Yep. Habe ich gestern eine Feier verpasst? Eine mit genug Alkohol, um
die Birnen noch jetzt erheblich zu beeinflussen. Ich bin auch ein wenig
über etliche der Antworten verwirrt. Ist immerhin eine Standardfrage,
auf die es eigentlich eine Standardantwort gibt. Statt dessen kommt erst
einmal ein Bündel Quatsch.
Stefan ⛄ F. schrieb:>> int8_t ergebnis = -3.0 * 5.0;> Das ist nicht OK, weil die Variable keine Negativen Zahlen speichern> kann. Das Resultat wird fehlerhaft sein.
Oh jeh...
(prx) A. K. schrieb:> Norbert schrieb:>> Da finde ich Ausgabezeile Zwei recht interessant.>> Weshalb?
Nun, wenn a und b erst nach int konvertiert würden und dann gerechnet
wird, sollte -1 zurück gegeben werden.
So aber wird uint8_t gerechnet und dann erst nach int konvertiert.
Thorsten S. schrieb:> Ich möchte b von a abziehen und auf das Ergebnis "reagieren">> if ((a-b)>=0)
Du möchtest also partout mit dem Kopf durch die Wand.
Aha, darum wird in den folgenden Beiträgen so unsäglich viel
herumgecastet.
Warum nicht einfach ein simpler Vergleich 'if (a>=b)...' oder warum
unbedingt als Operanden zweimal unsigned char und kein simpler int? Mußt
du so elend mit RAM sparen, wo das Ergebnis ohnehin negativ sein kann
und auch betragsmäßig größer als ein signed char?
W.S.
Norbert schrieb:> So aber wird uint8_t gerechnet und dann erst nach int konvertiert.
Falsch!
Es wird mit int gerechnet und beim return nach uint8_t konvertiert.
EAF schrieb:> Norbert schrieb:>> So aber wird uint8_t gerechnet und dann erst nach int konvertiert.>> Falsch!> Es wird mit int gerechnet und beim return nach uint8_t konvertiert.
… obwohl ein int Wert zurückgegeben wird? Interessant!
Norbert schrieb:> (prx) A. K. schrieb:>> Norbert schrieb:>>> Da finde ich Ausgabezeile Zwei recht interessant.>>>> Weshalb?> Nun, wenn a und b erst nach int konvertiert würden und dann gerechnet> wird, sollte -1 zurück gegeben werden.> So aber wird uint8_t gerechnet und dann erst nach int konvertiert.
Nö ...
Oder vielleicht doch, dank UB?
Norbert schrieb:> (prx) A. K. schrieb:>> Norbert schrieb:>>> Da finde ich Ausgabezeile Zwei recht interessant.>>>> Weshalb?> Nun, wenn a und b erst nach int konvertiert würden und dann gerechnet> wird, sollte -1 zurück gegeben werden.
Wie soll da jemals -1 zurück gegeben werden können? Die Funktion f1 hat
als return-Typ uint8_t. Der kann nicht -1 sein.
> uint8_t f1(uint8_t a, uint8_t b) { return a - b; }
Hier wird a - b in int gerechnet. Das Ergebnis ist vom Typ int und hat
für a=1 und b=2 den Wert -1. Allerdings hast du als Return-Typ der
Funktion ja uint8_t festgelegt, daher muss der Wert erst in diesen Typ
konvertiert werden.
> So aber wird uint8_t gerechnet und dann erst nach int konvertiert.
Falsche Schlussfolgerung.
(prx) A. K. schrieb:> Ich bin auch ein wenig über etliche der Antworten verwirrt. Ist immerhin> eine Standardfrage, auf die es eigentlich eine Standardantwort gibt. Statt> dessen kommt erst einmal ein Bündel Quatsch.
Das hab ich mir auch gedacht. Ist die integer promotion und wo sie sich
wie auswirkt, wirklich so vielen hier unbekannt?
Norbert schrieb:> Nun, wenn a und b erst nach int konvertiert würden und dann gerechnet> wird, sollte -1 zurück gegeben werden.
Beachte: Die zweite Ausgabezeile ist jene mit f1(). Eine Funktion, deren
Returnwert als uint8_t deklariert ist.
Norbert schrieb:> obwohl ein int Wert zurückgegeben wird? Interessant!
verstehst du dein eigenes Programm nicht?
Norbert schrieb:> uint8_t f1(uint8_t a, uint8_t b) { return a - b; }
Wo wird da ein int zurückgegeben?
Die Antwort: Nirgendwo!
(prx) A. K. schrieb:> Norbert schrieb:>> Nun, wenn a und b erst nach int konvertiert würden und dann gerechnet>> wird, sollte -1 zurück gegeben werden.>> Beachte: Die zweite Ausgabezeile ist jene mit f1(). Eine Funktion, deren> Returnwert als uint8_t deklariert ist.
Und der Wert wird dann nach int promoted für den Aufruf von printf,
welcher mit einem falschen Conversion Specifier stattfindet...
(prx) A. K. schrieb:> Das hat noch nicht einmal in jeder Zeit gestimmt, um die es in der> Retro-Diskussion im Nachbarthread geht.
Offenbar hast du Recht. Ich habe es gerade an PC ausgetestet.
Damit muss ich mit dringend im Detail befassen.
mh schrieb:> Oder vielleicht doch, dank UB?
Da sehe ich kein UB. Die Rechnung (a - b) ist einwandfrei definiert,
und eine Konvertierung in einen Typ ohne Vorzeichen ist es auch.
(prx) A. K. schrieb:> mh schrieb:>> Oder vielleicht doch, dank UB?>> Da sehe ich kein UB. Die Rechnung (a - b) ist einwandfrei definiert,> und eine Konvertierung in einen Typ ohne Vorzeichen ist es auch.
Nicht die Rechnung, der printf-Aufruf.
(prx) A. K. schrieb im Beitrag #6893419:
> mh schrieb:>> Und der Wert wird dann nach int promoted für den Aufruf von printf,>> welcher mit einem falschen Conversion Specifier stattfindet...>> Ist ein falscher Conversion Specifier für int<=>unsigned UB?
Wenn ich den Standard richtig verstehe (aus ISO/IEC 9899:201x, N1570):
1
7.21.6.1 The fprintf function
2
[...]
3
8) o,u,x,X The unsigned int argument is converted [...]
4
9) If a conversion specification is invalid, the behavior is undefined.282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
mh schrieb:> Und der Wert wird dann nach int promoted für den Aufruf von printf,> welcher mit einem falschen Conversion Specifier stattfindet...
%d wäre hier in allen Fällen korrekt, weil das Argument an printf immer
entweder schon vom Typ int ist, oder in diesen promoted wird. Bei %d
kommt ja auch in allen Fällen das erwartete Ergebnis raus.
Stefan ⛄ F. schrieb:> Damit muss ich mit dringend im Detail befassen.
Sehe ich auch so!
Deine Fantasie spielt dir öfter mal Streiche.
Ist aber keine Überraschung.
Geht wohl jedem mal so.
Dein Problem ist nur, dass du das dann VOR jeder Überprüfung, laut und
den Wissenden spielend, rausposaunst.
Tipp:
Einbildung und Realität sind kaum zu unterscheiden, wenn man nur lange
genug schon in den "falschen" Bahnen denkt.
mh schrieb:> Wenn ich den Standard richtig verstehe
Hast ja recht, habs auch gerade gesehen.
Ist allerdings reichlich unwahrscheinlich, dass bei gleicher Grösse was
anbrennt, bloss weil die Vorzeichenangabe falsch ist.
Rolf M. schrieb:> mh schrieb:>> Und der Wert wird dann nach int promoted für den Aufruf von printf,>> welcher mit einem falschen Conversion Specifier stattfindet...>> %d wäre hier in allen Fällen korrekt, weil das Argument an printf immer> entweder schon vom Typ int ist, oder in diesen promoted wird. Bei %d> kommt ja auch in allen Fällen das erwartete Ergebnis raus.
Bis C23 gibts noch ne andere Möglichkeit, wenn Compiler/CPU nicht
angegeben sind ... Integral Promotion promoted nicht immer zu int, in
speziellen Fällen auch unsigned int ;-)
64 Bit kann der printf() auf AVR offenbar nicht.
Was man hier dennoch schön sieht ist, dass die Größe des Ergebnisses
offenbar nicht immer mit den Operanden identisch ist. Es scheint
folgende Regel zu gelten:
Das Ergebnis hat immer die Größe der größten Operanden, aber mindestens
die Größe des "Standard" Integer. Der ist bei meinem PC 32 Bit groß und
bei AVR 16 Bit.
Ist das so korrekt?
EAF schrieb:> Dein Problem ist nur, dass du das dann VOR jeder Überprüfung, laut und> den Wissenden spielend, rausposaunst.
Ja, du hast Recht. Ich schäme mich dafür.
Stefan ⛄ F. schrieb:> Ist das so korrekt?
Schalt erstmal alle passenden Warnungen deines Compilers an und kümmer
dich um die Warnungen, die es wahrscheinlich gibt.
mh schrieb:> Integral Promotion promoted nicht immer zu int, in> speziellen Fällen auch unsigned int
Ist das nicht technisch identisch?
Stefan ⛄ F. schrieb:
8 Bit
1 + FF = 100 (4 bytes)
1 - FF = 100 (4 bytes)
Unabhängig ob die 4 Bytes nun int oder uint sind, erwarte ich 0x100 oder
0b100000000. Oder ist das etwa wieder falsch?
Alle die es noch nicht getan haben (und davon scheint es hier einige zu
geben), sollten sich
ISO/IEC 9899:2018, Abschnitt 6.3.1 (Arithmetic Operands).
(oder wahlweise auch den Draft N2176) zu Gemüte führen. Da sind die
Konvertierungen, um die es hier geht, vollständig spezifiziert. Der
Abschnitt ist mit zweieinhalb Seiten deutlich kürzer als dieser Thread
(und der wir immer länger und länger).
Wem das danach immer noch zu kompliziert ist, sollte von C auf Haskell
umsteigen. Da gibt es keine impliziten Konvertierungen. Bei Addition,
Subtraktion und den meisten anderen arithmetischen Operationen sind die
beiden Operanden und das Ergebnis grundsätzlich vom selben Typ. Wer sich
dieser Regel widersetzt, wird vom Compiler in seine Schranken verwiesen.
Stefan ⛄ F. schrieb:> mh schrieb:>> Integral Promotion promoted nicht immer zu int, in>> speziellen Fällen auch unsigned int>> Ist das nicht technisch identisch?
Nein ist es nicht.
> Stefan ⛄ F. schrieb:> 8 Bit> 1 + FF = 100 (4 bytes)> 1 - FF = 100 (4 bytes)>> Unabhängig ob die 4 Bytes nun int oder uint sind, erwarte ich 0x100 oder> 0b100000000. Oder ist das etwa wieder falsch?
Ich habe keine Ahnung was du hier fragst.
Yalu X. schrieb:> Wem das danach immer noch zu kompliziert ist, sollte von C auf Haskell> umsteigen.
Glaubst du, jemand der Integer Promotion in C nicht versteht, kommt mit
Haskell klar (also dem Rest der Sprache/Denkweise)?
Stefan ⛄ F. schrieb:> Stefan ⛄ F. schrieb:>> 64 Bit kann der printf() auf AVR offenbar nicht.>> (prx) A. K. schrieb:>> Welcher?>> Version 5.4.0
Ich meine nicht die Version. GCC kann 64-Bit Integer seit Ewigkeiten,
aber vielleicht nicht jeder andere Compiler für AVR.
In der Doku der avrlibc steht bei printf allerdings kein "%ll..." drin
und ein kurzer Blick in dessen Source legt nahe, dass dort der Hase im
Pfeffer liegt.
Stefan ⛄ F. schrieb:> Yalu X. schrieb:>> ISO/IEC 9899:2018, Abschnitt 6.3.1 (Arithmetic Operands).>> Leider ist das Dokument der Öffentlichkeit (also mir) nicht zugänglich.
Doch, aber du musst halt 198 CHF dafür berappen :)
> Der Draft ist dort:> https://teaching.csse.uwa.edu.au/units/CITS2002/resources/n2176.pdf
Super, dann hast du ja alle Informationen, die du brauchst, um
zukünftigen Überraschungen vorzubeugen :)
(prx) A. K. schrieb:> In der Doku der avrlibc steht bei printf allerdings kein "%ll..." drin> und ein kurzer Blick in dessen Source legt nahe, dass dort der Hase im> Pfeffer liegt.
Ich verwende die avr libc 1.2.0
Yalu X. schrieb:> Super, dann hast du ja alle Informationen, die du brauchst, um> zukünftigen Überraschungen vorzubeugen
Ja, ich lese gerade. Habe ich mir direkt in meine Büchersammlung
kopiert.
Stefan ⛄ F. schrieb:> Leider ist das Dokument der Öffentlichkeit (also mir) nicht zugänglich.
Drafts zu beispielsweise C99 oder C11 sind problemlos verfügbar und
unterscheiden sich vom Standard nicht signifikant.
Stefan ⛄ F. schrieb:> Es scheint> folgende Regel zu gelten:>> Das Ergebnis hat immer die Größe der größten Operanden, aber mindestens> die Größe des "Standard" Integer. Der ist bei meinem PC 32 Bit groß und> bei AVR 16 Bit.>> Ist das so korrekt?
Im Prinzip ja. Wobei es da dann noch ein paar Sonderfälle gibt.
(prx) A. K. schrieb:> Stefan ⛄ F. schrieb:>> 64 Bit kann der printf() auf AVR offenbar nicht.>> Welcher? https://gcc.gnu.org/wiki/avr-gcc#ABI
Was hat das ABI mit der Implementation von printf() zu tun?
Rolf M. schrieb:> Was hat das ABI mit der Implementation von printf() zu tun?
Habe ich auch nicht verstanden. Offenbar ist es eher eine Frage der
Implementierung von printf() also der library.
Der entscheidende Satz in der Spezifikation ist wohl
"If an int can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to an int;
otherwise, it is converted to an unsigned int."
Rolf M. schrieb:> Wobei es da dann noch ein paar Sonderfälle gibt.
Kannst du mir Beispiele nennen?
Ich frage nach, weil diese Spezifikation nicht gerade leichter Lesestoff
ist. Ich habe meinen Kopf leider mit anderen Programmiersprachen voll -
wegen der Arbeit. C ist bei mir nur Hobby.
(prx) A. K. schrieb:> Drafts zu beispielsweise C99 oder C11 sind problemlos verfügbar und> unterscheiden sich vom Standard nicht signifikant.
Ich habe ja jetzt mit Yalus Hilfe den Draft von C17 (Dokument N2176)
gefunden.
mh schrieb:> Yalu X. schrieb:>> Wem das danach immer noch zu kompliziert ist, sollte von C auf Haskell>> umsteigen.>> Glaubst du, jemand der Integer Promotion in C nicht versteht, kommt mit> Haskell klar (also dem Rest der Sprache/Denkweise)?
Zumindest sind dort alle Regeln sehr einfach gehalten (was sich in der
im Vergleich zu C deutlich kürzeren Sprachspezifikation ausdrückt).
Außerdem gibt es kaum Überraschungen zur Laufzeit, denn bevor es dazu
kommt, erhält man i.Allg. eine Fehlermeldung des Compilers, die recht
ausführlich erklärt, warum dieser den ihm vorgesetzten Quellcode nicht
umzusetzen kann.
Aber natürlich ist es auch in Haskell schwer, Programme zu schreiben.
Programmieren (egal in welcher Sprache) fällt niemanden in den Schoß,
man muss es erst mit viel Schweiß lernen :)
mh schrieb:> Ich habe keine Ahnung was du hier fragst.
Was ich meine ist, dass das Ergebnis als int und uint im
Speicher/Register identisch ist.
1
#include<stdio.h>
2
#include<stdint.h>
3
4
intmain()
5
{
6
uint8_ta=0;
7
uint8_tb=1;
8
9
uint16_td=a-b;
10
int16_te=a-b;
11
12
printf("d = %d = %X (%d bytes)\n",d,d,sizeof(d));
13
printf("e = %d = %X (%d bytes)\n",e,e,sizeof(e));
14
}
Ausgabe auf PC:
1
d = 65535 = FFFF (2 bytes)
2
e = -1 = FFFFFFFF (2 bytes)
Dezimal dargestellt erscheint der unsigned Integer falsch, denn er kann
keine negative Zahl darstellen.
Nur der signed Integer stellt das Ergebnis richtig dar. Hier gibt mir
printf() allerdings zu viele "F" aus.
Im Speicher sind es in beiden Fällen die gleichen 2 Bytes, nämlich FFFF.
Hier ist das auch nochmal alles zusammengefasst:
https://en.cppreference.com/w/c/language/conversionStefan ⛄ F. schrieb:> Dezimal dargestellt erscheint der unsigned Integer falsch, denn er kann> keine negative Zahl darstellen.
Mathematisch gesehen ja, aber C definiert durchaus, welcher Wert da
herauskommt.
> Nur der signed Integer stellt das Ergebnis richtig dar. Hier gibt mir> printf() allerdings zu viele "F" aus.
Weil hier eine sign extension durchgeführt wird.
Ein uint16_t mit dem Wert 65535 behält bei der Konvertierung in einen
32-Bit-Typ diesen Wert bei. Ein int16_t mit dem Wert -1 tut das auch.
Allerdings ist die interne Bitrepräsentation dieser beiden Werte zwar
vorher gleich, aber nachher unterschiedlich. Im einen Fall müssen die
zusätzlichen Bits mit 0 aufgefüllt werden, im anderen mit 1.
Hannes J. schrieb:> Einfach nicht voneinander abziehen oder erst nach dem Vergleich> abziehen:> if(a >= b) {> // Differenz garantiert >= 0> } else {> // Differenz negativ> }
War auch mein erster Gedanke. Die einfachste Lösung.
Scheint wohl hier nur keinen zu interessieren.
PittyJ schrieb:> Hannes J. schrieb:>> Einfach nicht voneinander abziehen oder erst nach dem Vergleich>> abziehen:>> if(a >= b) {>> // Differenz garantiert >= 0>> } else {>> // Differenz negativ>> }>> War auch mein erster Gedanke. Die einfachste Lösung.> Scheint wohl hier nur keinen zu interessieren.
Nach dem Motto: "Probleme nicht Lösen, sondern einen Workaround
benutzen".
PittyJ schrieb:> Scheint wohl hier nur keinen zu interessieren.
Quatsch!
Wurde doch sofort akzeptiert.
Siehe:
Thorsten S. schrieb:> Hannes J. schrieb:>> Einfach nicht voneinander abziehen oder erst nach dem Vergleich>> abziehen:>> Genial, manchmal hat man einen Knoten im Hirn...
Das ganze andere Getöse ist nur ein Nebenkriegsschauplatz.
PittyJ schrieb:> War auch mein erster Gedanke. Die einfachste Lösung.> Scheint wohl hier nur keinen zu interessieren.
Nunja, die daraus entstandene Diskussion scheint ja für so manchen hier
bitter nötig gewesen zu sein.
Rolf M. schrieb:> Nunja, die daraus entstandene Diskussion scheint ja für so manchen hier> bitter nötig gewesen zu sein.
Ja genau. Ich finde gut, dass das hier besprochen wurde. Zumindest für
mich war es lehrreich.
Rolf M. schrieb:> Nunja, die daraus entstandene Diskussion scheint ja für so manchen hier> bitter nötig gewesen zu sein.
Für mich auch 😀.
Diese Feinheiten sind einem Gelegenheitsprogrammierer meist nicht
bewusst und die werde ich mir auch nicht vollständig merken können.
Behält man die grundsätzliche Problemstellung wenigstens im Hinterkopf,
kommt man auch auf die Lösung von Hannes J.
Hannes J. schrieb:> Einfach nicht voneinander abziehen ...
oder auf eine andere Formulierung des Vergleichs. Oder sei es auch nur
im Fall einer Fehlfunktion einer der ersten Gedanken, an solchen Stellen
nochmals nachzudenken.
mh schrieb:>> Die einfachste Lösung.>> Scheint wohl hier nur keinen zu interessieren.>> Nach dem Motto: "Probleme nicht Lösen, sondern einen Workaround> benutzen".
Genau DAS ist C typisch.
Aber man kann sich dran gewöhnen - wie hier zu sehen ist.
W.S.