Hi, ich möchte zwei unsinged!!! Variablen vergleichen, aber das
funktioniert leider nicht so einfach, da bei > und < der Type in signed
umgewandelt wird.
Meine Frage nun wie kann ich das Kostengünstig ändern?
lg Blue
sd.putData(0xB0, 0x11); //schreibt 0x11 in EEprom an Adresse 0xB0
5
}
Mit AVR-Studio kann ich dann ja den EEProm ansehen bein debuggen und da
wird nichts an die Adresse 0xB0 geschrieben.
Ich nutze den avr-g++ als compiler da ich c++-Code habe.
lg blue
blue schrieb:> und da wird nichts an die Adresse 0xB0 geschrieben.
Dann würde ich aber sp.putData in Verdacht nehmen. Versuche mal, an der
Stelle
eine LED zu schalten oder mach Dir ein printf dort hin. Deine
Schlussfolgerung,
dass da eine Typumwandlung stattfindet, kann ich nicht nachvollziehen.
Wenn Du in der Simulation debuggst, wäre ich ebenfalls vorsichtig, mit
solchen
Annahmen :-)
Beste Grüße
Alfred
blue schrieb:> Mit AVR-Studio kann ich dann ja den EEProm ansehen beim debuggen und da> wird nichts an die Adresse 0xB0 geschrieben.
Wenn du debuggst, wird da nichts geschrieben, oder springt er gar nicht
in die if Abfrage?
An allem anderen kann es nicht liegen, das funktioniert. auch das
sd.putData(0xB0, 0x11) funktioniert.
wenn es keine Typumwandlung in c++ bei solch einem Vergleich gibt, kann
es dann am avr-g++ liegen?
Das habe ich ja anstelle des avr-gcc eingestellt im avr-Studio.
Wenn es daran liegt, wie kann ich avr-studio dazu bringen meinen
c++-code zu compilieren?
ok, habs eben gefunden, es lag wirklich am avr-g++.
ich nutze jetzt das Makefile, das ich auch zum aufspielen auf den
Roboter nutze.
Danke für die schnelle Hilfe.
lg blue
blue schrieb:> ok, habs eben gefunden, es lag wirklich am avr-g++.
Das ist ja sehr schön, dass dein Problem jetzt gelöst ist. Aber warum
teilst du jetzt nicht dein Wissen mit der Community, deren Hilfe du
zuvor haben wolltest? Es kann ja durchaus sein, dass irgendwann
irgendjemand ein ähnliches Problem hat.
Also, um mein neugefundenes Wissen allen zu Teil kommen zulassen. ;-)
Das Problem: Vergleich von zwei uint8_t hat nicht funktioniert.z.B.
0xFF>0x00 hat false ergeben.
Ursache: Das Problem lag an meiner Nutzung von AVR-Studio und avr-g++.
Da ich einfach die Adresse für avr-gcc duch die von avr-g++ ersetzt
habe. Die main blieb aber eine main.c.
Lösung:1.: avr-gcc lassen wie es ist. Die .c im Source-Ordner löschen
und durch einen .cc ersetzen. oder
Lösung:2.: Ebenfalls die .c durch eine .cc ersetzen und ein eindeses
externes Makefile nutzen.(Nutze ich, da ich ein Makefile habe, das ich
zum Download auf meinen Robter auch nutze und somit alle Einstellungen
nicht immer neu machen muss)
@Frank M.: Sie haben sicher Recht, ich glaube es lag an meiner
Verwendung des g++ und nicht am g++ selbst, weiß es aber nicht genau.
Danke für die kritische Betrachtung.
Grüße blue
blue schrieb:> Ursache: Das Problem lag an meiner Nutzung von AVR-Studio und avr-g++.> Da ich einfach die Adresse für avr-gcc duch die von avr-g++ ersetzt> habe. Die main blieb aber eine main.c.
Was ist "die Adresse für avr-gcc"?
> Lösung:1.: avr-gcc lassen wie es ist. Die .c im Source-Ordner löschen> und durch einen .cc ersetzen. oder>> Lösung:2.: Ebenfalls die .c durch eine .cc ersetzen und ein eindeses> externes Makefile nutzen.(Nutze ich, da ich ein Makefile habe, das ich> zum Download auf meinen Robter auch nutze und somit alle Einstellungen> nicht immer neu machen muss)
Das verstehe ich ehrlich gesagt alles nicht. Auch bleibt unklar, was das
mit einem falschen Vergleichsergebnis zweier uint8_t zu tun haben soll.
Offenbar wurde im Makefile einfach "avr-gcc" durch "avr-g++" als Text
ersetzt.
Dass schon dadurch die Funktion des Codes verändert werden soll, halte
ich auch für unglaubwürdig. Abgesehen von wenigen Ausnahmen (z.B. neuen
Schlüsselworten) ist ein korrekter C-Code auch ein korrekter C++-Code.
Meine Kristallkugel sagt: Das Codebeispiel ist wahrscheinlich falsch.
blue hat in seinem Quelltext möglicherweise "char" statt "uint8_t"
verwendet, vielleicht kennt er gar nicht den Unterschied. Wenn dann die
eine Compiler-Einstellung ein nacktes "char" defaultmäßig als "signed",
die andere als "unsigned" betrachtet, kommt es halt zu einem solchen
Verhalten. Das ist dann wirklich kein Problem des Compilers, sondern des
Programmierers.
Compiler produzieren selbst im Idealfall nur Programme, die das tun, was
im Quelltext steht. Compiler, die stattdessen Programme erzeugen, die
das tun, was der Programmierer "eigentlich wollte", hat noch keiner
erfunden. ;)
Lieber Alfred,
ich glaube ich kann sagen, wie blue darauf kommt:
Ich zitiere:
However integral promotion can take place when operands are of the same
type. For example, when two signed chars are added together, both are
converted to type int before addition and the result of the operation is
of type int. This process is known as integral promotion and it occurs
even with unary operators such as "-" or "~".
The rules of integral promotion say that:
A char, short, bit-field (all signed or unsigned) or an enum value is
converted to an int if an int is able to represent all values of the
original type, otherwise the value is converted to unsigned int.
In practice this means that the value of the original object is usually
converted to an int but possibly to an unsigned int if the original data
type is unsigned and of the same size as an int. For example in an
implementation with an 8 bit char, a 16 bit short and a 32 bit int, all
chars and shorts will be promoted to signed int values. However if both
short and int are only 16 bits, an unsigned short will be promoted to an
unsigned int.
Anmerkung:
integral promotion findet immer statt! Das hat nichts mit balancing zu
tun, bei dem Typen aneinander angeglichen werden, sondern dient dazu,
die Anzahl der Implementierungen für die Operatoren überschaubar zu
halten.
Also muss ein unsigned char in ein int gewandelt werden, wenn int größer
als 8 Bit ist. Ich denke nicht, dass es irgendeine Implementierung mit
8-Bit ints gibt, bin mir aber im Moment nicht sicher, ob das erlaubt ist
oder nicht.
Alfred schrieb:>> da bei > und < der Type in signed>>> umgewandelt wird.>>>> Hallo blue,>>>> bitte sag, wie kommst Du darauf?>>>> Beste Grüße>>>> Alfred
> Meine Kristallkugel sagt: Das Codebeispiel ist wahrscheinlich falsch.> blue hat in seinem Quelltext möglicherweise "char" statt "uint8_t"> verwendet, vielleicht kennt er gar nicht den Unterschied.
Das ist für mich die plausibelste Erklärung.
> Also muss ein unsigned char in ein int gewandelt werden,> wenn int größer als 8 Bit ist.
Eigentlich in einen unsigned int, aber so kleinlich wollen wir mal nicht
sein. Der springende Punkt: Ein int kann alle Werte eines unsigned char
aufnehmen. Von daher passiert bei
if( 0xFF > 0x00 )
genau das erwartete: Der int Wert 127 wird mit dem int Wert 0 verglichen
und als solcher als größer bewertet.
Nur dann, wenn die Variablen vom Datentyp char sind UND char per Default
ein signed char ist, erklärt sich das vom TO beobachtete Verhalten ganz
natürlich.
Kann natürlich auch sein, dass der eigentliche Fehler
> ich hab folgendes ausprobiert:
1
uint8_tx=0;
2
uint8_ty=0xff;
3
4
if(x<y){
5
sd.putData(0xB0,0x11);//schreibt 0x11 in EEprom an Adresse 0xB0
6
}
in sd.putData liegt. Um abzuklären, ob der Vergleich wie gewollt
funktionioniert, ist die Verwendung einer komplexen Funktion wie
sd.putData nicht unbedingt das Mittel der Wahl. Eine Testumgebung soll
immer so einfach wie möglich sein, damit sie nicht selbst durch Fehler
das Testergebnis verfälscht.
Karl heinz Buchegger schrieb:> Eigentlich in einen unsigned int
Wieso? Nein, der Wert 0xFF wird zu 0x00FF als singned int, denn ein
signed int kann alle Werte eines uint8_t fassen. Das ist aber immer
noch größer als 0x0000.
Irgendwo in der Ecke wird sich unser TE aber wohl schon verrannt
haben, nur hat er so viel mit trial&error programmiert, dass er
mittlerweile gar nicht mehr nachvollziehen kann, was denn da schräg
war.
Jörg Wunsch schrieb:> Karl heinz Buchegger schrieb:>> Eigentlich in einen unsigned int>> Wieso? Nein, der Wert 0xFF wird zu 0x00FF als singned int, denn ein> signed int kann alle Werte eines uint8_t fassen.
Ja, da hab ich jetzt geschlafen.
Ich brauch noch einen Kaffee.
Karl heinz Buchegger schrieb:>> Meine Kristallkugel sagt: Das Codebeispiel ist wahrscheinlich falsch.>> blue hat in seinem Quelltext möglicherweise "char" statt "uint8_t">> verwendet, vielleicht kennt er gar nicht den Unterschied.>> Das ist für mich die plausibelste Erklärung.
ACK. Wenn man einem signed char 0xFF zuweist, bekommt man -1. Und,
normalerweise, eine Compilerwarnung, die man, normalerweise, ignoriert,
um sich dann in einem Forum öffentlich zu wundern.
>>>> Also muss ein unsigned char in ein int gewandelt werden,>>> wenn int größer als 8 Bit ist.>>> Eigentlich in einen unsigned int, aber so kleinlich wollen wir mal nicht>> sein.
NACK. Solange, und da hast Du natürlich Recht, alle Werte repräsentiert
werden können, werden signed-typen bevorzugt. Ich könnte jetzt
versuchen, die entsprechenden Stellen in der ISO-Doc zu suchen, aber
wichtig ist das wirklich nicht. Unsigned Int wird nur verwendet, wenn
z.B. sizeof(unsigned char)==sizeof(int), aber das müsste schon ein sehr
merkwürdiger Compiler sein.
> Der springende Punkt: Ein int kann alle Werte eines unsigned char> aufnehmen. Von daher passiert bei>> if( 0xFF > 0x00 )>> genau das erwartete: Der int Wert 127 wird mit dem int Wert 0 verglichen> und als solcher als größer bewertet.
(ACK) statt 127 lies: 255, aber das ändert inhaltlich genau nix.
> Nur dann, wenn die Variablen vom Datentyp char sind UND char per Default> ein signed char ist, erklärt sich das vom TO beobachtete Verhalten ganz> natürlich.
ACK.
stefan hennig schrieb:>> if( 0xFF > 0x00 )>>>> genau das erwartete: Der int Wert 127 wird mit dem int Wert 0 verglichen>> und als solcher als größer bewertet.>> (ACK) statt 127 lies: 255, aber das ändert inhaltlich genau nix.
Irgendwie ist heute bei mir der Wurm drinnen.
Gut dass ihr auf mich aufpasst. :-)
stefan hennig schrieb:> Anmerkung:> integral promotion findet immer statt! Das hat nichts mit balancing zu> tun, bei dem Typen aneinander angeglichen werden, sondern dient dazu,> die Anzahl der Implementierungen für die Operatoren überschaubar zu> halten.
Ist auf den meisten Compilern auch kein Problem, da int normalerweise
der "natürlichen Größe" der CPU entsprechen sollte und daher ein
kleinerer Typ eh nicht schneller wäre. Das paßt nur leider nicht für
8-Bit-Prozessoren, da int mindestens 16 Bit breit sein muß.
stefan hennig schrieb:> Also muss ein unsigned char in ein int gewandelt werden, wenn int größer> als 8 Bit ist.
Und unsigned char kleiner als int. Aber eigentlich muss der Compiler
es nicht so machen. Es gibt in C die "as-if rule", nach der der Compiler
Dinge beliebig anders machen kann, als von der Norm vorgegeben, solange
nur das Ergebnis gleich ist (genauer gesagt das "observable behaviour").
> Ich denke nicht, dass es irgendeine Implementierung mit 8-Bit ints gibt,
Ja, nämlich avr-gcc mit der Option -mint8.
> bin mir aber im Moment nicht sicher, ob das erlaubt ist oder nicht.
Ist es nicht. Aber ein char, der 32 Bit breit ist, wäre erlaubt, sofern
alle anderen Typen auch mindestens so groß sind.
Karl heinz Buchegger schrieb:> stefan hennig schrieb:>>>> if( 0xFF > 0x00 )>>>>>> genau das erwartete: Der int Wert 127 wird mit dem int Wert 0 verglichen>>> und als solcher als größer bewertet.>>>> (ACK) statt 127 lies: 255, aber das ändert inhaltlich genau nix.>> Irgendwie ist heute bei mir der Wurm drinnen.> Gut dass ihr auf mich aufpasst. :-)
Protest (ich habe an der Ecke schon mal lange gesucht und bin deshalb
"gebranntes Kind")!
0xff ist nicht 255, sondern -1.
if (0xff > 0x00) ...
wird promoted zu int:
0x00 gibt 0 - wie erwartet
0xff wird als integer aufgefaßt und gibt -1.
Damit gilt: 0xff < 0x00.
Um derartige eklige Kleinigkeiten zu verhindern, schreibe ich 0x0ff,
sobald ich einen 8-Bit-Wert bezeichne, der in dezimaler Schreibweise 255
bedeuten soll.
Bernhard
Bernhard R. schrieb:> 0xff ist nicht 255, sondern -1.
0xff ist eine Integer-Konstante mit dem Wert 255. Erst auf dem Umweg
über (signed) char kann daraus -1 werden. Egal wie abgebrannt du bist.
Wenn's anders ist, dann ist das kein Standard-C, sondern irgendwas
Anderes oder ein Programmfehler.
Zwischen 0xff und 0x0ff und 0x0000000000000ff besteht exakt garkein
Unterschied.
Bernhard R. schrieb:> 0xff wird als integer aufgefaßt und gibt -1.
Nur, wenn Deine Chars signed sind, aber dann ist der Fehler bei der
Zuweisung passiert, nicht bei der Erweiterung.
Deshalb: keine Chars verwenden, ohne Signedness anzugeben und
Compilerwarnungen ernst nehmen und wenn möglich mit der höchsten
Warnstufe übersetzen. (Geht manchmal nicht, wenn man Bibliotheken
verwenden muss, die einen dann zumüllen).
Oder, um die hier herrschende Verwirrung komplett zu machen:
Annahme: char ist 8 Bit breit, int ist 16 Bit breit.
1
unsignedcharuca=0xFFu;
2
unsignedintuia=0xFFu;
3
4
if(uca<-2){
5
// wird nie erreicht
6
}
7
8
if(uci<-2){
9
// wird immer erreicht
10
}
Grund: Im ersten Fall wird uca in den (signed) Integer 255 gewandelt. Im
zweiten Fall wird -2 als 0xFFFEu repräsentiert und anschließend werden
zwei unsigned Integer verglichen.
Alles streng nach ISO. Ich weiß auch nach mehr als 10 Jahren im Geschäft
immer noch nicht, warum man ausgerechnet C für Embedded Programmierung
nimmt...
Jörg Wunsch schrieb:> Wieso? Nein, der Wert 0xFF wird zu 0x00FF als singned int, denn ein> signed int kann alle Werte eines uint8_t fassen.
Wenn 0xFF aber schon signed ist, dann wird daraus 0xFFFF
A. K. schrieb:> Bernhard R. schrieb:>>> 0xff ist nicht 255, sondern -1.>> 0xff ist eine Integer-Konstante mit dem Wert 255.
Und das wiederrum ist so, weil alle hexadezimalen Konstanten den
Datentyp unsigned haben.
8 und 0x8 sind also 2 verschiedene Dinge:
8 ist ein signed Integer
0x8 ist ein unsigned Integer
(Übrigens: oktale Konstanten sind ebenfalls unsigned)
Karl heinz Buchegger schrieb:>> 0xff ist eine Integer-Konstante mit dem Wert 255.> Und das wiederrum ist so, weil alle hexadezimalen Konstanten den> Datentyp unsigned haben.
Selbst wenn es ein signed int wäre, wäre der Wert immer noch 255, da
INT_MAX mindestens gleich 32767 ist, 255/0xff also immer im
Wertebereich von int darstellbar ist, ohne zu einem Überlauf zu führen.
Andreas
Man sollte ab und an einmal ausmisten...
und wenn es das eigene Gehirn ist!
Vor langen Jahren - damals galt noch "real programmers dont ANSI" - war
ich auf ein sehr debug-intensives Problem - incl. einiger Nachtschichten
- gelaufen. Dieses Problem hing zusammen mit
- Nicht-ANSI-C-Compiler
- Hexadezimal-Konstanten
- Vorzeichen-Behandlung
- ...
Jedenfalls war es für mich Anlaß für folgende Aktionen und Denkfehler:
- Hex-Konstanten erhielten eine führende "Schutz-Null", um sie als
positiven Wert zu kennzeichnen.
- Hex-Konstanten "propagieren" ihr Vorzeichen.
Bernhard
> Ich bin mir da gar nicht so sicher.
0x8000 ist ein unsigned, d.h. das ist die Zahl 32768
x als 32 Bit Wert, kann diese Zahl aufnehmen, also 32768
y ist die Hälfte davon: also 16384
Stimmt, aber irgendetwas war da. Ich habe es noch einmal nachgeschlagen.
Etwas, was nicht tut, was man naiverweise erwartet, ist das:
1
uint32_tx=1<<15;
Weil "1" vom Compiler als ein signed int betrachtet wird, ist "1 << 15"
gleich -32768, wird dann (signed) zu 32 BIt aufgeblasen und in x steht
am Ende 0xFFFF8000.
Frank M. schrieb:> Aber nur auf Systemen, wo int == int16_t ;-)
Ist C nicht herrlich :-)
Die lobende Erwähnung in "Real Programmers don't use PASCL" hat es sich
wirklich redlich verdient.
Detlev T. schrieb:> Frage: Wenn C schrecklich ist, muss dann C++ nicht noch schrecklicher> sein? ;)
Außerdem müsste B besser und D noch schlimmer sein. :-)
stefan hennig schrieb:> Deshalb: keine Chars verwenden, ohne Signedness anzugeben
Außer denen, wo Text drin gespeichert werden soll.
Detlev T. schrieb:> Frage: Wenn C schrecklich ist, muss dann C++ nicht noch schrecklicher> sein? ;)
Und C# ist so schrecklich, daß man es hinter Gitter stecken wollte.
Leider ist es aber irgendwie vor dem Gitter gelandet. ;-)
Karl heinz Buchegger schrieb:> 8 ist ein signed Integer> 0x8 ist ein unsigned Integer> (Übrigens: oktale Konstanten sind ebenfalls unsigned)
Nixda. Ist beides wertabhängig, anfangend mit signed int, nur geht es
unterschiedlich weiter:
Dezimal: int => long int => unsigned long int
Oktal/Hex: int => unsigned int => long int => unsigned long int
0x4000 ist also signed int,
0x8000 bei 16bit unsigned int.
A. K. schrieb:> Karl heinz Buchegger schrieb:>>> 8 ist ein signed Integer>> 0x8 ist ein unsigned Integer>> (Übrigens: oktale Konstanten sind ebenfalls unsigned)>> Nixda.
Mea Culpa.
Platsch (das war die Seifenblase die soeben zerplatz ist)
Du hast recht.
(Sowohl der Draft als auch gcc stimmen mit dir überein)
Das wär auch zu einfach gewesen, wenn es da eine einfche Regel gäbe.
0x4000 ist tatsächlich signed, 0x8000 ist tatsächlich unsigned
Hmm
Das bedeutet für mich: Lieber einen Suffix anhängen als auf irgendwelche
Werte vertrauen.
1
6.4.4.1 Integer constants
2
3
5 The type of an integer constant is the first of the corresponding
Hex Konstanten geben sich das volle Programm.
Das ist bei einem Wechsel von 16-Bit int zu 32-Bit int dann speziell
ganz besonders lustig, wenn man so Spielchen mit Bitverschieberein
macht, die davon abhängen ob das im Original signed oder unsigned war
( 0x4000 << 1 ) >> 1
liefert dann auf einem 32 Bit System ein anderes Ergebnis als auf einem
16 Bit System.
OK. Um der Wahrheit genüge zu tun: Schiebereien mit signed Werten sind
ja sowieso undefined. Von daher ist das gedeckt (Ich darf kein Ergebnis
erwarten und als richtig definieren). Aber lästig könnte das schon sein.
Darüber hab ich mir ehrlich gesagt noch nie wirklich Gedanken gemacht,
aber das sollte ich mal tun, was da so an Fallstricken im Verborgenen
lauert. Im Moment ist meine Conclusio: Häng einen Suffix an wenn du
unsigned willst, dann gibts keine Überraschungen.
Danke für die Aufklärung.
Jörg Wunsch schrieb:> Außerdem müsste B besser und D noch schlimmer sein. :-)
Für B ist das anzunehmen, jedenfalls aus Sicht von Ritchie, sonst hätte
er es bei B belassen und nicht C draus gemacht.
Was D angeht bin ich etwas anderer Ansicht als dessen Erfinder. Für
einen Nachfolger von C m.E. deutlich zu kurz gesprungen.
Bernhard R. schrieb:> - gelaufen. Dieses Problem hing zusammen mit> - Nicht-ANSI-C-Compiler> - Hexadezimal-Konstanten> - Vorzeichen-Behandlung
Yep, vor ANSI war dieses Thema ein bischen offen. Es gab 2 Fraktionen.
Die Einen bestanden schon damals auf auf value preservation, wie ANSI es
später definierte, die Anderen favorisierten sign preservation, bei der
im Zweifelsfall stets "unsigned" gewinnt. Es war schon damals klüger,
sich nicht von solchen Feinheiten abhängig zu machen. Ich hatte mir
daher den Spass erlaubt, beides zu implementieren, d.h. wählbar.