Hallo Leute,
ich kapier es irgendwie nicht. Es geht mal wieder um das Thema Array als
Pointer einer Funktion mitzugeben.
AVR GCC V4.19
folgendes habe ich vor:
Nun habe ich gegoogelt und gelesen und ua das gefunden:
1
voidrs232_recv(uint8_ti_pau8Data[],
2
uint8_t*i_u8Len)
Das soll aber wohl dasselbe sein. Aber es bleibt bei der Warnung.
wie bekomme ich die Warnungen weg? Was im Detail mache ich falsch?
PS: Ja, ich kann auch die Länge direkt mitgeben und die (neue) Länge als
Return-wert zurückgeben. Aber so muss es doch auch gehen...
Matthias Lipinsky schrieb:> void rs232_recv ( uint8_t *i_pau8Data,> uint8_t *i_u8Len )> re232_recv( scDiag.u8RxLen, &scDiag.au8RxMsg);
Entweder deine Bezeichnungen sind missverständlich, oder das ist genau
verkehrt rum.
i_pau8Data ist doch wohl der Pointer zu den Daten. Und die sind ja wohl
im Array au8RxMsg und nicht in u8RxLen. Die Funktion will zuerst den
Pointer zu den Daten und als zweites den Pointer zum Längenbyte.
1
re232_recv(scDiag.au8RxMsg,&scDiag.u8RxLen);
wäre für mich daher logischer.
Und dann passt es auch mit dem Adressoperator.
Matthias Lipinsky schrieb:>>Entweder deine Bezeichnungen sind missverständlich, oder das ist genau>>verkehrt rum.>> Richtig. Das ist hier aus Versehen vertauscht.>>
1
>rs232_recv(scDiag.au8RxMsg,&scDiag.u8RxLen);
2
>
>> ... liefert aber dieselben beiden Warnungen.. Warum?
Dieselben?
Also die hier
zumindest die erste müsste jetzt anders lauten. Das müsste ebenfalls
eine discards qualifier warnung sein.
> Hat das was mit dem Volatile der Struktur zutun?
ja, hat es.
Ein
volatile uint8_t *
ist nun mal was anderes als ein
uint8_t *
im ersten ist noch immer die Information drinnen, dass das Ziel volatile
ist. Im zweiten nicht.
d.h. wenn die Pointer an die Funktion übergeben werden, wird innerhalb
der Funktion dieses volatile ignoriert. Schlecht ausgedrückt. Es geht
beim Aufruf der Funktion 'verloren'. Innerhalb der Funktion darf der
Compiler wieder hemmungslos optimieren. Das wolltest du aber unter
Umständen nicht. Sonst hättest du das Ding ja erst gar nicht volatile
gemacht.
>Dieselben?
Hab ich nicht geprüft. War nur ein CTRL+C/V Fehler hier in den Post.
>ja, hat es.>Ein> volatile uint8_t *>ist nun mal was anderes als ein> uint8_t *>im ersten ist noch immer die Information drinnen, dass das Ziel volatile>ist. Im zweiten nicht.
Hm ok. Aber volatile soll doch verwendet werden, bei Variablen, die an
verschiedenen Stellen (Ints) genutzt werden.
Ist der Gedanke, diese Variablen alle in einer Strkutur
zusammenzupacken, und diese volatile zu kennzeichnen, falsch?
Nehm ich das volatile weg, sind die Warnungen weg.
Matthias Lipinsky schrieb:> Nehm ich das volatile weg, sind die Warnungen weg.
oder schreib das volatile in der Funktion hin
> Hm ok. Aber volatile soll doch verwendet werden, bei Variablen, die an> verschiedenen Stellen (Ints) genutzt werden.
kommt darauf an ob im Hauptprogramm und in den INTs darauf zugegriffen
wird oder nur ein verschieden INTs
Matthias Lipinsky schrieb:> Hm ok. Aber volatile soll doch verwendet werden, bei Variablen, die an> verschiedenen Stellen (Ints) genutzt werden.
Na ja.
volatile soll in erster Linie benutzt werden um dem Compiler klar zu
machen, dass er seine Optimize-Finger von den Variablen lassen soll.
Bei Wert-Übergaben aus einer ISR heraus durch globale Variablen ist das
ein Muss. Aber innerhalb einer ISR wäre das zb harmlos, wenn die
Variable nicht volatile wäre.
> Ist der Gedanke, diese Variablen alle in einer Strkutur> zusammenzupacken, und diese volatile zu kennzeichnen, falsch?
Überhaupt nicht.
Wenn es keinen grossen Unterschied in der recv Funktion macht, dann
kannst du ja ein
1
voidrs232_recv(volatileuint8_t*i_pau8Data,
2
volatileuint8_t*i_u8Len)
3
{
4
...
draus machen.
Wenn dir das das Optimierungspattern in der Funktion über den Jordan
haut, UND es ok ist, dass innerhalb der Funktion der Compiler
hemmungslos optimieren darf, dann kannst du auch beim Aufruf das
volatile wegcasten
Aber eines steht auf jeden Fall fest. So wie im Original, fällt beim
Aufruf ein volatile unter den Tisch und der Compiler weist dich darauf
hin. Es liegt jetzt an dir zu entscheiden, ob das ok ist (und du daher
den Compiler mit einem "Ruhe-Jetzt"-Cast ruhigstellst) oder ob du in der
Funktion dieses volatile respektieren musst.
Oder aber vielleicht muss ja gar nicht die komplette Struktur volatile
sein? Wer weiss? Gibt es denn Potential, dass der COmpiler in diesen
beiden Members mit der Optimierung daneben hauen kann?
>Oder aber vielleicht muss ja gar nicht die komplette Struktur volatile>sein? Wer weiss? Gibt es denn Potential, dass der COmpiler in diesen>beiden Members mit der Optimierung daneben hauen kann?
Hm..
Der Kontext ist etwa so:
Eine Funktion (hier im Beispiel i2c_write) bekommt Daten/Infos was ist
zutun mit den EIngangsvariablen. Das wird lib-intern in einer Struktur
abgelegt und per ISR(s) etc in der Lib im Hintergrund bearbeitet. Wenn
das fertig ist, dann wird das über ein Zeiger auf eine "Fertig" Variable
gemeldet.
SO hier etwa:
Matthias Lipinsky schrieb:> Ich weiß eben nicht genau, ob der Compiler sowas per Optimierung> zerwürgt...
Unter uns Klosterschwestern.
In einem Array hat der Compiler normalerweise sowieso schlechte Karten,
sich einzelne Array Elemente in einem Register vorzuhalten. Soviele CPU
interne Register hat der nicht.
Die neuralgischen Punkte sind sowas
1
uint8_ti;
2
3
voidmain()
4
{
5
...
6
7
while(1)
8
{
9
if(i>5)
10
{
11
PORTD|=8;
12
}
13
14
// X ....
15
}
d.h. kleine Hauptschleife, wenig Variablen
Sobald an der Position X da komplexerer Code reinkommt und der COmpiler
vor lauter Variablen in Register laden und umladen nichts mehr frei hat,
dann geht da sowieso nichts mehr mit Schleifenübergreifender
Optimierung. Um
1
voidmain()
2
{
3
...
4
for(i=0;i<40;i++)
5
machwasmitmsg[i];
6
...
soweit zu optimieren, dass ein fehlendes volatile (obwohl es eigentlich
korrekt wäre!) sich auswirkt, da hat der COmpiler auf einem AVR 0
Chancen. Soviele CPU Register gibt es gar nicht, dass er das machen
könnte und für jedes einzelne Array-Element ein Register reserviert.
Aber:
Ich denke mal nicht, dass deine recv Funktion stark beeinträchtigt wird,
wenn du das volatile ergänzt. Daher würde ich es reintun.
>Ich denke mal nicht, dass deine recv Funktion stark beeinträchtigt wird,>wenn du das volatile ergänzt. Daher würde ich es reintun.
Ich hab es jetzt komplett weggelassen und geht noch.
Wenn ich länger drüber nachdenke, glaube ich, kanns fast überall
weglassen. Wenn ich mit einer (zB) i2c_write Funktion einen Zeiger in
die interne Struktur schaffe um damit zu arbeiten, und aussen warte bis
diese fertig ist, dann ändert sich der Zeiger währenddem ja nicht. Und
somit sollte das volatile unnötig sein. Ich werde es wohl nur bei den
internen Statusvariablen ergänzen..
Matthias Lipinsky schrieb:> die interne Struktur schaffe um damit zu arbeiten, und aussen warte bis> diese fertig ist
normalerweise sind diese Flag Variablen der Knackpunkt.
Die sollten volatile sein. Das ist wie eine Semaphore, wo 1 Semaphore
benutzt wird um eine ganze Datenstruktur in der Multitasking
Programmierung abzusichern.
>> in der Abfrage als volatile kennzeichne, damit sie wirklich immer von> der SPeicherzelle gelesen wird...Matthias Lipinsky schrieb:> Hm ok. Aber volatile soll doch verwendet werden, bei Variablen, die an> verschiedenen Stellen (Ints) genutzt werden.
Ich habe den Eindruck, dass du ein grundsätzliches Missverständnis
bezüglich des "die an verschiedenen Stellen (Ints) genutzt werden" hast.
Wenn du in einer aufgerufenen Funktion eine Variable änderst und dann in
der übergeordneten Funktion diese testest, dann gibt es nicht den
geringsten Grund für ein volatile.