portTickTypexItemValue;/*< The value being listed. In most cases this is used to sort the list in descending order. */
4
volatilestructxLIST_ITEM*pxNext;/*< Pointer to the next xListItem in the list. */
5
volatilestructxLIST_ITEM*pxPrevious;/*< Pointer to the previous xListItem in the list. */
6
void*pvOwner;/*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
7
void*pvContainer;/*< Pointer to the list in which this list item is placed (if any). */
8
};
9
typedefstructxLIST_ITEMxListItem;/* For some reason lint wants this as two separate definitions. */
10
11
structxMINI_LIST_ITEM
12
{
13
portTickTypexItemValue;
14
volatilestructxLIST_ITEM*pxNext;
15
volatilestructxLIST_ITEM*pxPrevious;
16
};
17
typedefstructxMINI_LIST_ITEMxMiniListItem;
18
19
/*
20
* Definition of the type of queue used by the scheduler.
21
*/
22
typedefstructxLIST
23
{
24
volatileunsignedportBASE_TYPEuxNumberOfItems;
25
volatilexListItem*pxIndex;/*< Used to walk through the list. Points to the last item returned by a call to pvListGetOwnerOfNextEntry (). */
26
volatilexMiniListItemxListEnd;/*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
27
}xList;
Bei folgender Zeile bekomme ich eine Warnung bezüglich der benützung von
strict-aliasing rules:
Entweder
-fno-strict-aliasing als Option für GCC angeben (Nachteil: manchmal
schlechteres Optimierungsergebnis)
oder
Optimierung auf maximal -O1 beschränken (Nachteil: fast immer
schlechteres Optimierungsergebnis)
oder
wilde Pointer-Casts vermeiden (Nachteil: machmal Denkarbeit
erforderlich ;-))
Am einfachsten (und saubersten) wäre natürlich, als Listenend-Item
ebenfalls ein xListItem anstatt eines xMiniListItems zu verwenden.
Dann brauchst du keine Casts und alles ist 100%ig typsicher. Ich nehme
aber an, du möchtest im Listenend-Item den Speicherplatz der Elemente
pvOwner und pvContainer einsparen.
Zunächst etwas zum logischen Zusammenhang der von dir benutzten
Datentypen:
xListItem ist sozusagen eine Erweiterung von xMiniListItem. In C++
würde man xListItem von xMiniListItem ableiten und könnte dann
problemlos (ohne Cast) einem xMiniListItem-Pointer einen
xListItem-Pointer zuweisen, nur umgekehrt nicht. Die Liste würde man
dann aber nicht aus xListItems sondern aus xMiniListItems (dem
allgemeineren Datentyp) aufbauen, d.h. alle pxNext- und
pxPrevious-Pointer wären vom Typ xMiniListItem.
Bei dir ist die Zuweisung allerdings anders herum: Du weist einem
xListItem-Pointer (pxList->xListEnd.pxNext) einen xMiniListItem-
Pointer zu (pxList->xListEnd). Das ist unschön, weil du ohne Cast und
ohne Compiler-Warnung auf
pxList->xListEnd.pxNext->pvOwner
zugreifen könntest, was aber Müll produziert, da pxNext in diesem Fall
auf ein xMiniListItem zeigt, das das Element pvOwner gar nicht
besitzt.
Deswegen würde ich das Ganze folgendermaßen umstrukturieren:
- Bau die Liste wie oben beschrieben aus xMiniListItems auf.
- Ersetze die ersten drei Elemente von xListItem durch ein einzelnes
Element vom Typ xMiniListItem, das ja selber diese drei Elemente
enthält, z.B. so:
struct xLIST_ITEM {
xMiniListItem mini;
void *pvOwner, *pvContainer;
};
Dadurch drückst du aus, dass xListItem eine Erweiterung von
xMiniListItem ist und die strict-aliasing-Warnung bei Casts bleibt
wahrscheinlich aus, weil der Compiler m.W. nur solche Variablen als
nicht-aliased annimmt, deren Datentypen überhaupt nichts miteinander
zu tun haben, sich also auch nicht gegenseitig enthalten.
- Das Listenend-Item ist nach wie vor vom Typ xMiniListItem.
- Sämtliche Listenoperationen, die auf dem Umbiegen von Pointer
beruhen (Einfügen, Löschen usw.), werden nun auf dem einheitlichen
Datentyp xMiniListItem ausgeführt. Dazu bedarf es keinerlei Casts.
- Beim Einfügen eines neuen xListItems (nennen wir es 'item'),
brauchst du einen xMiniListItem-Pointer, der auf diese Struktur
zeigt. Du erhältst ihn ebenfalls ganz ohne Cast über
&item.mini
- Der einzige Fall, wo du noch einen Cast brauchst, ist beim Zugriff
auf die Elemente pvOwner und pvContainer über einen xMiniListItem-
Pointer. Dieser Zugriff birgt eine gewisse Gefahr, da nicht von
vorneherein klar ist, ob das Item diese Elemente auch tatsächlich
enthält. Die Unterscheidung erfolgt deiner Aussage zufolge über den
xItemValue, d.h. vor dem Zugriff auf pvOwner und pvContainer wirst
du eine Abfrage machen, ob es ich bei dem Item nicht um das End-Item
handelt. Damit erreichst du, dass der Cast (immer eine potenziell
gefährliche Aktion) genau dort gemacht wird, wo auch die Abfrage zur
Beseitigung dieser Gefahr steht.
- Schließlich würde ich die Namen der Datenstrukturen ändern, da diese
nicht mehr gut zum veränderten Aufbau passen, und zwar
xListItem in xListItemWithContent (oder so ähnlich, vielleicht
geht's kürzer)
und
xMiniListItem in xListItem
Erweiterte Datenstrukturen sollten möglichst auch erweiterte Namen
haben. Dies ist durch obige namensänderungen geschehen.
Ich hoffe, das Ganze war wenigstens halbwegs verständlich geschrieben.
Wenn nicht (was wahrscheinlich ist ;-)), kannst ja nochmal nachfragen.
@Simon:
Ich glaube, gast programmiert in C (nicht in C++) und ist einfach zu
faul, jedesmal das 'struct' vor die Datentypen zuschreiben, deswegen
die typedefs.
Nun werde ich das Beispiel, ist ja ein Auszug aus dem FreeRTOS - also
nicht von mir Programmiert - einmal Aufzeichnen, was da genau gemacht
wird, und mit den von dir Erhaltenen Informationen verstehen versuchen,
denn genau da scheitert es bei mir noch etwas.
Aufzuzeigen, wie soetwas in C++ gelöst wird, war schon sehr hilfreich,
normalerweise Programmiere ich nämlich nur SPS'n in Structured Text,
welches sehr Objektorientiert ist.
Hatte zwar C in der Schule, aber wenn man selten etwas damit macht, dann
scheitert es leider schnell am Verständnis.
Werde mich wieder melden, wenn ich es durchblickt - oder auch nicht
durchblickt - habe.
mfg. Gast
Natürlich fehlt wiedermal eine Edit-Funktion.
Ich vermute einmal, dass es einen guten Grund hat, wieso das so gelöst
wurde -> Speicherverbrauch?
mfg. Gast
gast wrote:
> Natürlich fehlt wiedermal eine Edit-Funktion.>> Ich vermute einmal, dass es einen guten Grund hat, wieso das so gelöst> wurde -> Speicherverbrauch?
Nein, das liegt an dir. Wenn du dich registrierst und ordentlich
einloggt, dann hast du die Editfunktion.
Strafe muß sein...
oder habe ich da jetzt einen Denkfehler?
Ich glaube ich muss zugeben, dass ich da noch immer nicht ganz so
durchblicke, wie ich es eigentlich sollte.
-> 10 Minuten später:
So nochmals mit aufzeichnen, ja ich habe einen Denkfehler, denn mit
pxList->xListEnd.pxNext greife ich ja auf ein Element der Struktur
xListItem zu und mit pxList->xListEnd auf ein Element der Struktur
xMiniListItem, wenn ich das richtig verstehe.
Die vorgeschlagene Änderung von dir xMiniListItem in xListItem zu
integrieren, halte ich für ausgezeichnet, werde ich dann mal durch den
Compiler jagen, ob er da meckert und zudem muss ich noch schauen, wie es
sich mit dem Rest der Source verhält.
Die Programmierer eines RTOS sind ja auch nicht fehlerfrei ^^
mfg. Gast
> Die Programmierer eines RTOS sind ja auch nicht fehlerfrei ^^
Das können sie auch gar nicht. Was nach heutigem C Standard noch
richtig ist, kann morgen schon ein Fehler sein ;-)
Naja, ganz so schlimm ist's dann doch nicht. Aber gerade diese
Aliasing-Regeln, die u.a. besagen, dass man auf ein Objekt eines
bestimmten Datentyps nicht über einen Pointer auf einen anderen
Datentyp zugreifen darf (es gibt aber Ausnahmen), gab es nicht immer.
Ich glaube sogar, sie kamen erst mit ISO C99. Führer waren solche
Konstrukte, wie du sie gezeigt hast, ganz normal und nicht einmal
schlechter Programmierstil. Deswegen kann man solche "Ungenauigkeiten"
(um den hässlichen Begriff "Fehler" zu vermeiden) nicht unbedingt den
Programmieren anlasten.
Auch heute wissen viele Programmierer noch nichts von diesen Regeln,
die dem Compiler bspw. klare Anweisungen darüber geben, wann und für
wie lange Variablenwerte in Registern gehalten werden können, um
schnelleren Code zu erzeugen. GCC kennt und benutzt diese Regeln seit
Version 3.4.1, also erst seit ca. 3 Jahren. Ich vermute, dass sie in
vielen anderen Compilern bis heute noch nicht implementiert sind.
Mir ist aber nicht ganz klar, was der Grund für deine Überlegungen
ist, wobei Neugier und Interesse an solchen Dingen natürlich immer
anzuerkennen ist. Ich bin anfänglich davon ausgegangen, dass du das
FreeRTOS ändern oder erweiteren möchtest (oder dass du am Ende
vielleicht einer der Entwickler bist :-)). Jetzt habe ich eher den
Eindruck, dass du den FreeRTOS-Code einfach nur verstehen möchtest.
Wenn du FreeRTOS nur benutzen möchtest, ist der pragmatischste Weg
sicher, -fno-strict-aliasing zu benutzen.
> Hm, was würde der Compiler denn machen, wenn ich einfach auf ( void * )> caste?
Das verhindert wahrscheinlich die Ausgabe der Warnung, aber du
verbaust dem Compiler damit evtl. Optimierungsmöglichkeiten.
> Sollte in C nicht eientlich der Typ des Pointers egal sein?
Datentypen (auch bei Pointern) ermöglichen dem Compiler, die Absichten
des Programmierers besser zu "verstehen" und dadurch den Coder besser
zu optimieren oder ggf. Warn- und Fehlermeldungen auszugeben, wenn an
diesen Absichten etwas widersprüchlich erscheint und so den
Programmierer bei der Fehlersuche zu unterstützen.
Guter Stil es es deswegen, die Datentypen immer so treffend wie
möglich zu wählen, mit Casts zu sparsam umzugehen und Void-Pointer nur
in Ausnahmefällen zu verwenden.
gast wrote:
> Hm, was würde der Compiler denn machen, wenn ich einfach auf ( void * )> caste?
Du würdest das Symptom beheben statt der Ursache. Laut C-Standard
darfst du einen void * nur als Vehikel benutzen, um ihn hinterher
wieder auf den gleichen Typ zu casten, der er vorher mal war.
Kann also gut sein, dass du damit die Compilerwarnung beseitigen
würdest -- aber nur, indem du GCC damit austrickst, weil er sich
unmöglich intern alle Typen merken kann, die mal in einen void *
konvertiert worden sind.
> Wäre nicht auch ein>> pxList->xListEnd.pxNext = (xListItem) ( ( xListMiniItem * )> &( pxList->xListEnd ) );>> legitim?
Nein. Der Cast (xListMiniItem *) ist überflüssig, da der Ausdruck
rechts davon ja schon ein Pointer auf auf xListMiniItem ist. Der Cast
(xListItem) würde einen Pointer in eine Struktur casten, das geht
nicht. Oder hast du nur den Stern vergessen und es sollte (xListItem
*) heißen? Dann bleibt aber, wenn man den überflüssigen Cast weglässt,
gasts ursprünglicher Ausdruck übrig, der zu besagter Warnung führt.