AtmelStudio 7 - Long variable übergeben

#5193676
Lesenswert?

Frohes Allerheiligen,

Ich bin relativ neu in AVRC. Bei einem Aktuellen Projekt musste ich 
einen long integer an eine Routine übergeben und darin damit rechnen. 
Nach langer Fehlersuche stellte sich heraus, dass Atmel Studio ein 
Problem damit hat long integer Zahlen an eine Routine zu übergeben. Wen 
man die Zahl direkt als Dezimalzahl als Parameter eingibt, wird sie 
unter einem Zahlenwert von  32768 (Bit15) ins falsche Byte geschrieben. 
Wenn ich sie aber vorher in eine variable schreibe, und diese dann als 
Parameter angebe funktioniert die Übertragung. (Wie man auf den Bildern 
sehen kann). Ist dieses Verhalten normal?
Angehängte Dateien:
Gast #5193678
Lesenswert?

Gabriel M. schrieb:
> Ist dieses Verhalten normal?

nein, könnte aber nur ein Ansicht Problem beim Debugger sein.

Da der Code nichts sinnvolles macht, wird vermutlich alles wegoptimiert. 
Dann sieht der Debugger nichts sinnvolles.

Außerdem hat das Studio kein Problem sondern wenn überhaupt der Compiler 
(GCC)
#5193697
Lesenswert?

Peter II schrieb:
> könnte aber nur ein Ansicht Problem beim Debugger sein.

Ich hatte das problem vorher schon auf dem µC, weshalb ich dieses 
einfache testprogramm geschrieben habe

Peter II schrieb:
> Da der Code nichts sinnvolles macht, wird vermutlich alles wegoptimiert.
> Dann sieht der Debugger nichts sinnvolles.

Optimizer ist aus.

Peter II schrieb:
> Außerdem hat das Studio kein Problem sondern wenn überhaupt der Compiler
> (GCC)

Ja
(Firma: RUB) #5193736
Lesenswert?

Bitte gewoehne dir diesen Mist mit int, long, etc. ab und nimm die 
Datentypen aus der stdint.h. ((u)int8_t, (u)int16_t, (u)int32_t, usw.)
Da weiss jeder gleich beim raufschauen, wie gross der Wertebereich ist, 
und der Wertebereich ist damit auf allen Platformen immer gleichgross. 
int ist auf dem AVR 2 Byte gross, bei long muesste ich erst mal 
nachschauen.

Wie schnell man sich mit int, long, etc. ins Knie schiesst kann man an 
der Referenzimplementierung von MD5 (RFC1321) sehen. Die Funktioniert 
naemlich nur auf x86 richtig, aber nicht mehr auf x86_64.
https://de.wikipedia.org/wiki/Message-Digest_Algorithm_5#Referenzimplementation

Stefan E. schrieb:
> Die Zeile, auf die der Pfeil zeigt, ist eigentlich die Zeile, die als
> nächstes ausgeführt wird.
So siehts aus.

Stefan E. schrieb:
> Mach mal ein zusätzliches NOP dahinter und
> mache einen zusätzlichen Step (oder setze den Breakpoint auf das NOP).
Oder einfach ein return; :)
#5193749
Lesenswert?

Ich würde die Funktionmal vor main() schieben, damit beim Aufruf auch 
bekannt ist, daß sie einen long Parameter hat. Ohne dies wird long als 
64Bit übergeben, 10 aber als 16bit, denn ist ist ja nicht 10L.

Vermutlich wird der Compiler aber einige Anmerkungen (Warnings) dazu 
gemacht haben. Sollte man gelegentlich lesen ;-)
Gast #5193753
Lesenswert?

Carl D. schrieb:
> Ich würde die Funktionmal vor main() schieben, damit beim Aufruf auch
> bekannt ist, daß sie einen long Parameter hat. Ohne dies wird long als
> 64Bit übergeben, 10 aber als 16bit, denn ist ist ja nicht 10L.

sehr guter Hinweis.

> Vermutlich wird der Compiler aber einige Anmerkungen (Warnings) dazu
> gemacht haben. Sollte man gelegentlich lesen ;-)

angeblich keine Warnungen.
#5193765
Lesenswert?

Peter II schrieb:
> Carl D. schrieb:
>> Ich würde die Funktionmal vor main() schieben, damit beim Aufruf auch
>> bekannt ist, daß sie einen long Parameter hat. Ohne dies wird long als
>> 64Bit übergeben, 10 aber als 16bit, denn ist ist ja nicht 10L.
>
> sehr guter Hinweis.
Bei mir hat sich der Nebel eben längst gelichtet.


>> Vermutlich wird der Compiler aber einige Anmerkungen (Warnings) dazu
>> gemacht haben. Sollte man gelegentlich lesen ;-)
>
> angeblich keine Warnungen.
Dazu kenn ich den GCC zu gut, um das zu glauben.

BTW:
Die Typen aus inttypes.h sind natürlich wichtig, wenn Algoritmen auf 
bestimmten Bitlängen basieren, helfen aber nicht bei mangelndem 
Sprachverständnis.
Beitrag #5193791 wurde von einem Moderator gelöscht.
#5193860
Lesenswert?

Carl D. schrieb:
> Ich würde die Funktionmal vor main() schieben, damit beim Aufruf auch
> bekannt ist, daß sie einen long Parameter hat. Ohne dies wird long als
> 64Bit übergeben, 10 aber als 16bit, denn ist ist ja nicht 10L.

Ok Funktioniert, wieder was dazugelernt

Carl D. schrieb:
> Vermutlich wird der Compiler aber einige Anmerkungen (Warnings) dazu
> gemacht haben. Sollte man gelegentlich lesen ;-)

Stimmt, er gibt eine Warnung, habe sie vorher im Simulator Fenster 
übersehen

Vielen Dank an alle :)
#5193882
Lesenswert?

Peter II schrieb:
> Irgendwer schrieb:
>> Probier mal:
>> routine(10L);
>> routine((long)10);
>
> vermutlich verschwindet der Effekt, aber das eigentliche Problem ist
> damit nicht behoben.
>
> Es muss auch mit 10 ohne cast oder Suffix gehen.

Das Problem ist, daß eine nicht deklarierte Funktion (->Prototyp), denn 
sie wird erst nach Verwendung definiert, in C erlaubt ist, aber dann 
davon ausgegangen wird, daß die Parameter vom 
(implementierungsabhänigen) Typ int sind, hier 16bit. Deswegen warnt der 
GCC, und macht es dann falsch oder richtig, je nach Gusto des Benutzers.

Für mich macht er es nur richtig, denn er soll 16bit übergeben und da 
paßt 10 gut rein. Würde man 100000 übergeben wollen, dann würde er 
wieder warnen, weil das nicht in 16bit paßt. Ob später jemand die 
Funktion ganz anders definiert, interessiert dann nicht mehr.
Aber wie gesagt, es hagelt genügend Warnungen um dem Rätsel auf die Spur 
zu kommen, im 10er- und 100000er-Fall.
BTW, volatile wurde als Lösungsansatz noch gar nicht vermutet :-)
Persönliche Seite #5197092
Lesenswert?

Damit ein Wert korrerkt übergeben werden kann, ist i.d.R ein korrekter 
Prototyp notwendig.  Daher:

-Wmissing-prototypes -Wstrict-prototypes

zu den Compileroptionen hinzufügen und entsprechende Warnungen beheben. 
Oder gar:

-Werror=missing-prototypes -Werror=strict-prototypes

Ohne Prototyp hat ein Aufruf foo (0) implizit int foo (int) also 
Prototyp, auch wenn ein long übergeben wird, d.h. Ohne vorherige 
Deklaration ist foo (0L) immer noch int foo (int).
#5197261
Lesenswert?

Kaj G. schrieb:
> Bitte gewoehne dir diesen Mist mit int, long, etc. ab und nimm die
> Datentypen aus der stdint.h. ((u)int8_t, (u)int16_t, (u)int32_t, usw.)
> Da weiss jeder gleich beim raufschauen, wie gross der Wertebereich ist,
> und der Wertebereich ist damit auf allen Platformen immer gleichgross.

Es ist außer für direkte Kommunikation auf Binärebene nie zwingend 
erforderlich, die Variablen auf feste Größen zu zwingen. Das kann auch 
zu suboptimalem Code führen. Erforderlich ist, dass man versteht, wie 
die Typen funktionieren und welche Wertebereiche sie garantiert haben - 
und dass man beim Definieren einer Variable kurz darüber nachdenkt. 
Sinnvoll können auch die [u]int_least*_t und [u]int_fast*_t sein. Da hat 
man seinen Wertebereich auch garantiert, aber man gibt dem Compiler mehr 
Raum zum Optimieren.

> int ist auf dem AVR 2 Byte gross, bei long muesste ich erst mal
> nachschauen.

long ist auf allen konformen Compilern mindestens 32 Bit groß.
Das Problem hier ist ja auch nicht die Größe von int oder long, sondern 
dass die Funktion vor Verwendung nicht deklariert war.

Carl D. schrieb:
> Für mich macht er es nur richtig, denn er soll 16bit übergeben und da
> paßt 10 gut rein. Würde man 100000 übergeben wollen, dann würde er
> wieder warnen, weil das nicht in 16bit paßt. Ob später jemand die
> Funktion ganz anders definiert, interessiert dann nicht mehr.

Dann kommt dafür aber die Warnung, dass diese Definition der Funktion 
nicht mit der vorherigen (in diesem Fall impliziten) Deklaration 
übereinstimmt.

> Aber wie gesagt, es hagelt genügend Warnungen um dem Rätsel auf die Spur
> zu kommen, im 10er- und 100000er-Fall.
> BTW, volatile wurde als Lösungsansatz noch gar nicht vermutet :-)

Man kann nicht jedes "seltsame Variablenproblem" mit volatile 
erschlagen.
(Firma: RUB) #5197325
Lesenswert?

Rolf M. schrieb:
> Es ist [...] nie zwingend erforderlich
Das habe ich auch nicht gesagt. Aber der Vorteil ist erheblich:
Jeder, der sich den Code anschaut sieht auf anhieb welche Wertebereiche 
angenommen werden koennen, ohne das sich der Leser Gedanken darueber 
machen muss auf welcher Platform der Code laeuft.

Und wie das Beispiel von MD5 zeigt, scheint es ja doch hin und wieder 
erforderlich zu sein, eben um die korrekte Funktion zu garantieren.

Aber was rede ich hier. Sicherheit und korrekte Funktion interessiert ja 
eh niemanden.

Rolf M. schrieb:
> Sinnvoll können auch die [u]int_least*_t und [u]int_fast*_t sein. Da hat
> man seinen Wertebereich auch garantiert, aber man gibt dem Compiler mehr
> Raum zum Optimieren.
Ja, deswegen schrieb ich auch "usw." mit dazu :-)
#5197342
Lesenswert?

Kaj G. schrieb:
> Das habe ich auch nicht gesagt. Aber der Vorteil ist erheblich:
> Jeder, der sich den Code anschaut sieht auf anhieb welche Wertebereiche
> angenommen werden koennen, ohne das sich der Leser Gedanken darueber
> machen muss auf welcher Platform der Code laeuft.

Mindest-Wertebereiche können auch für die eingebauten Typen angenommen 
werden. Beispiel: Ein long ist wie schon gesagt mindestens 32 Bit breit. 
Beim int sind es nur 16 Bit. Brauche ich also Werte größer als 32k, 
nehme ich einen long und keinen int.

> Und wie das Beispiel von MD5 zeigt, scheint es ja doch hin und wieder
> erforderlich zu sein, eben um die korrekte Funktion zu garantieren.

Wie gesagt: Erforderlich ist, zu wissen, welche Garantien die Typen 
einem geben und insbesondere auch, welche sie nicht geben. Wenn man das 
nicht beachtet und einfach davon ausgeht, dass die Datentypen so sind 
wie auf der Plattform, die man aktuell vor sich hat, wird das ganze eben 
nicht portabel.

> Aber was rede ich hier. Sicherheit und korrekte Funktion interessiert ja
> eh niemanden.

Doch, die interessiert schon. Aber man muss ja nicht unbedingt die 
Schrauben mit dem Hammer in die Wand schlagen, nur weil man keine Lust 
hat, den Umgang mit dem Akkuschrauber zu lernen.
#5198291
Lesenswert?

Rolf M. schrieb:
> Sinnvoll können auch die [u]int_least*_t und [u]int_fast*_t sein. Da hat
> man seinen Wertebereich auch garantiert, aber man gibt dem Compiler mehr
> Raum zum Optimieren.

Mal interessehalber: welcher Compiler optimiert da denn? Die 
Implementierungen der least - und fast - Typen, die ich so kenne ( sind 
allerdings nicht viele), sind reine typedefs auf Typen aus der stdint. 
Der Compiler selber kennt least- und fast gar nicht.

Oliver
#5198298
Lesenswert?

Oliver S. schrieb:
> sind reine typedefs auf Typen aus der stdint

das ist schon die Optimierung. Viele "moderne" Befehlssätze (namentlich 
ARM) implementieren Arithmetik (nur) auf Basis der "natürlichen" 
Hauptregisterbreite und müssen - wenn man ihnen was anderes gibt - 
aufwendige extend- und truncate-Befehle einfügen. Der Sachverhalt ändert 
sich ja nicht, kann also direkt per typedef vorgegeben werden.
#5198302
Lesenswert?

Oliver S. schrieb:
> Rolf M. schrieb:
>> Sinnvoll können auch die [u]int_least*_t und [u]int_fast*_t sein. Da hat
>> man seinen Wertebereich auch garantiert, aber man gibt dem Compiler mehr
>> Raum zum Optimieren.
>
> Mal interessehalber: welcher Compiler optimiert da denn? Die
> Implementierungen der least - und fast - Typen, die ich so kenne ( sind
> allerdings nicht viele), sind reine typedefs auf Typen aus der stdint.
> Der Compiler selber kennt least- und fast gar nicht.

War vielleicht etwas falsch ausgedrückt. Was ich meinte, war, dass die 
_fast-Typen ggf. auch größer sein können als die angegebene Größe, falls 
dadurch die Nutzung auf dem vorliegenden Prozessor effizienter ist.
#5198332
Lesenswert?

Rolf M. schrieb:
>> BTW, volatile wurde als Lösungsansatz noch gar nicht vermutet :-)
>
> Man kann nicht jedes "seltsame Variablenproblem" mit volatile
> erschlagen.

ich hoffe der humoristische Teil meines Vorschlags wurde verstanden.

Abgesehen von unvermeidbaren, aber seltener auftretenden 
Compilerfehlern, bekommt man eigentlich nur das in MaschinenCode 
umgesetzt, was man in Hochsprache formuliert hat. Und wenn man genauer 
nachdenkt, was man da geschrieben, stellt man nicht selten fest, was das 
für ein Blödsinn war.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren