Co można zobaczyć między otwarciem i zamknięciem })
({
jest wyrażeniem oświadczenie - niestandardowa funkcja kompilatora GCC, który pozwala na umieszczanie oświadczeń związku w wyrażeniach C. Wynikiem takiego wyrażenia instrukcji jest ostatnia instrukcja wyrażenia wewnątrz ({})
. W twoim przypadku będzie to &__get_cpu_var(var)
.
Operator &
zostanie zastosowany do wyniku podwyrażenia __get_cpu_var(var)
. Oznacza to, że __get_cpu_var
zwraca wartość l. Jeśli rzeczywiście jest to C, to __get_cpu_var
musi być także makrem, ponieważ w języku C funkcje nie mogą zwracać wartości l.
Operator tworzy wskaźnik (wynik całego wyrażenia instrukcji), który następnie jest dereferencji przez operatora *
obecny na samym początku powyższej definicji makra. Tak więc powyższe makro jest zasadniczo równoważne z wyrażeniem *&__get_cpu_var(var)
.
Niektórzy mogą zapytać, dlaczego jest on zaimplementowany jako *&__get_cpu_var(var)
, a nie tylko __get_cpu_var(var)
. Odbywa się to w ten sposób, aby zachować dokładność wyniku __get_cpu_var(var)
. Wynik wyrażenia instrukcji jest zawsze wartością r, nawet jeśli ostatnie wybranie wewnątrz ({})
było lwartością. W celu zachowania dokładności wyniku zastosowano znaną sztuczkę *&
.
Ta sztuczka nie jest w żaden sposób ograniczona do wyrażeń oświadczeń GCC. Jest stosunkowo często używany w zwykłym codziennym programowaniu C. Na przykład, wyobraź sobie, że masz dwie zmienne
int a, b;
i chcesz napisać wyrażenie wróci albo a
lub b
jako lwartości (powiedzmy chcemy przypisać 42
do niego) w zależności od selektora zmiennej select
. Naiwny próba może wyglądać następująco
(select ? a : b) = 42;
to nie będzie działać, ponieważ w języku C operator ?:
traci lvalueness swoich argumentów. Wynikiem jest wartość r, której nie można przypisać. W tej sytuacji *&
trik przychodzi na ratunek
*(select ? &a : &b) = 42;
i teraz działa zgodnie z przeznaczeniem.
To jest dokładnie jak i dlaczego oryginalna definicja makra z plakatu zawiera pozornie redundantną aplikację z *
i &
.Z tego powodu można użyć powyższej get_cpu_var
makro po obu stronach o assgnment
something = get_cpu_var(something);
get_cpu_var(something) = something;
bez tej sztuczki byłbyś w stanie wykorzystać get_cpu_var
na prawej stronie tylko.
W języku C++ ten sam efekt uzyskuje się, korzystając z referencji. W C nie mamy referencji, więc zamiast tego używamy takich sztuczek.
, więc * (...) jest typografią do wyniku? * edited.noted i dzięki. –
Więc to w zasadzie zwraca '* & __get_cpu_var (var)' - ale dlaczego po prostu nie zwracają '__get_cpu_var (var)'? Jakiś rodzaj kontroli czasu kompilacji? – Anthales
@Anthales: Dodałem odpowiedź powyżej – AnT