Forum: Compiler & IDEs AtmelStudio 7 - Long variable übergeben


von Gabriel M. (gabse)


Angehängte Dateien:

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?

von Peter II (Gast)


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)

von Gabriel M. (gabse)


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

von Peter II (Gast)


Lesenswert?

Gabriel M. schrieb:
> Ich hatte das problem vorher schon auf dem µC, weshalb ich dieses
> einfache testprogramm geschrieben habe

teste mal mit:
1
Routine(long l)
2
{
3
   long v = l;
4
   if (v == 10 ) {
5
      v = 1;
6
   }
7
}


und schau ob er ins if geht.

von Stefan E. (sternst)


Lesenswert?

Die Zeile, auf die der Pfeil zeigt, ist eigentlich die Zeile, die als 
nächstes ausgeführt wird. Mach mal ein zusätzliches NOP dahinter und 
mache einen zusätzlichen Step (oder setze den Breakpoint auf das NOP).

von Gabriel M. (gabse)


Lesenswert?

Peter II schrieb:
> und schau ob er ins if geht.

bei
1
 routine(10);
nicht,

bei
1
long l = 10;
2
routine(1);
schon

Stefan E. schrieb:
> Mach mal ein zusätzliches NOP dahinter und
> mache einen zusätzlichen Step (oder setze den Breakpoint auf das NOP).

hilft auch nichts

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Gabriel M. schrieb:
> bei
>
>  routine(10);
>
> nicht,
>
> bei
>
> long l = 10;
> routine(1);
>
> schon

gibt es Warnungen beim Compiler? Alle Warnungen eingeschaltet (-Wall ?)

von Kaj G. (Firma: RUB) (bloody)


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

von Gabriel M. (gabse)


Lesenswert?

Peter II schrieb:
> gibt es Warnungen beim Compiler? Alle Warnungen eingeschaltet (-Wall ?)

Warnungen sind Eingeschalten, es gibt aber keine

Kaj G. schrieb:
> nimm die
> Datentypen aus der stdint.h.

Hab ich probiert, selber fehler

von Carl D. (jcw2)


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

von Peter II (Gast)


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.

von Carl D. (jcw2)


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.

: Bearbeitet durch User
von Irgendwer (Gast)


Lesenswert?

Gabriel M. schrieb:
> bei
> routine(10);
> nicht,

Probier mal:
routine(10L);
routine((long)10);

von Peter II (Gast)


Lesenswert?

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.

Beitrag #5193791 wurde von einem Moderator gelöscht.
von Peter II (Gast)


Lesenswert?

Dieter F. schrieb im Beitrag #5193791:
> Schau mal hier,
>
> https://gcc.gnu.org/wiki/avr-gcc
>
> was bei einem 8-Bit-Prozessor mit GCC long bedeutet (oder versuche mal
> "long long" :-) )

was meinst du damit? eine 10 passt doch wohl in 32bit rein.

von Dieter F. (Gast)


Lesenswert?

Peter II schrieb:
> was meinst du damit?

Habe ich zurückgezogen, weil nur bei einer Direktive "-mint8" so.
Vegiss es bitte einfach ...

von Gabriel M. (gabse)


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

von Carl D. (jcw2)


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

von Johann L. (gjlayde) Benutzerseite


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

: Bearbeitet durch User
von Rolf M. (rmagnus)


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.

von Kaj G. (Firma: RUB) (bloody)


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

von Rolf M. (rmagnus)


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.

von Paul B. (paul_baumann)


Lesenswert?

Rolf M. schrieb:
> Erforderlich ist, zu wissen, welche Garantien die Typen
> einem geben und insbesondere auch, welche sie nicht geben.

Also: Im Prinzip genau so, wie bei einem Autohändler.

Flücht
:)
MfG Paul

von Oliver S. (oliverso)


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

von Markus F. (mfro)


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.

von Rolf M. (rmagnus)


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.

von Carl D. (jcw2)


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.

von Peter D. (peda)


Lesenswert?

Gabriel M. schrieb:
> Ist dieses Verhalten normal?

Ja.
Ohne Deklaration nimmt der Compiler als Argument int an und gibt eine 
entsprechende Warnung aus.
Mit routine( 10UL ) kannst Du ihm sagen, daß er ein long übergeben soll.

Die saubere Lösung ist aber, alle Funktionen vor ihrer ersten Benutzung 
zu deklarieren.

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.