Was Sie zwischen der Öffnung sehen ({
und Schließen })
ist eine Anweisungsausdruck - eine nicht standardisierte Funktion des GCC-Compilers, die es ermöglicht, zusammengesetzte Anweisungen in C-Ausdrücke einzubetten. Das Ergebnis eines solchen Anweisungsausdrucks ist die allerletzte Ausdrucksanweisung innerhalb der ({})
. In Ihrem Fall wäre das &__get_cpu_var(var)
.
Le site &
Operator wird auf das Ergebnis von __get_cpu_var(var)
Unterausdruck. Das bedeutet, dass __get_cpu_var
gibt einen l-Wert zurück. Wenn dies tatsächlich C ist, dann __get_cpu_var
muss ebenfalls ein Makro sein, da in der Sprache C Funktionen keine lWerte zurückgeben können.
Le site &
Operator erzeugt einen Zeiger (das Ergebnis des gesamten Anweisungsausdrucks), der dann von einem anderen Operator dereferenziert wird. *
Operator, der ganz am Anfang der obigen Makrodefinition steht. Das obige Makro ist also im Wesentlichen gleichwertig mit dem *&__get_cpu_var(var)
Ausdruck.
Manch einer mag sich fragen, warum sie als *&__get_cpu_var(var)
und nicht nur __get_cpu_var(var)
. Dies geschieht auf diese Weise, um die lvalueness des Ergebnisses von __get_cpu_var(var)
. Das Ergebnis des Anweisungsausdrucks ist immer ein r-Wert, auch wenn der letzte Satz innerhalb der ({})
ein l-Wert war. Um die L-Wertigkeit des Ergebnisses zu erhalten, wird die bekannte *&
Trick angewendet wird.
Dieser Trick ist in keiner Weise auf GCC-Anweisungsausdrücke beschränkt. Er wird relativ häufig in der alltäglichen C-Programmierung verwendet. Stellen Sie sich zum Beispiel vor, Sie haben zwei Variablen
int a, b;
und Sie wollen einen Ausdruck schreiben, der entweder a
o b
als l-Wert (sagen wir mal, wir wollen 42
zu), abhängig von der Selektorvariable select
. Ein naiver Versuch könnte folgendermaßen aussehen
(select ? a : b) = 42;
Dies wird nicht funktionieren, da in der Sprache C die ?:
Operator verliert die l-Wertigkeit seiner Operanden. Das Ergebnis ist ein r-Wert, der nicht zugewiesen werden kann. In dieser Situation wird der *&
Der Trick kommt zur Rettung
*(select ? &a : &b) = 42;
und jetzt funktioniert es wie vorgesehen.
Genau aus diesem Grund enthält die Makrodefinition des ursprünglichen Posters eine scheinbar redundante Anwendung von *
et &
. Aus diesem Grund können Sie die oben genannten get_cpu_var
Makro auf beiden Seiten eines Assgnments
something = get_cpu_var(something);
get_cpu_var(something) = something;
Ohne diesen Trick könnten Sie nur get_cpu_var
auf der rechten Seite.
In der Sprache C++ wird derselbe Effekt durch die Verwendung von Referenzen . In C haben wir keine Verweise, also verwenden wir stattdessen Tricks wie diesen.