2012-04-15 13 views
6

get_cpu_var marcro który jest zdefiniowany jako poniżejzawiłych #define makro napotkał w źródła jądra Linux

29 #define get_cpu_var(var) (*({       \ 
30   extern int simple_identifier_##var(void);  \ 
31   preempt_disable();        \ 
32   &__get_cpu_var(var); })) 

wydaje niezrozumiałe be.I jestem zakładając, że był to jeden rodzaj funkcji makro, które zwracają zmienny wskaźnik (na podstawie gwiazdka), czy jest to jakiś wskaźnik funkcji. Czy jestem w pobliżu? Czy ktoś mógłby mnie oświecić?

Odpowiedz

15

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.

+0

, więc * (...) jest typografią do wyniku? * edited.noted i dzięki. –

+0

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

+1

@Anthales: Dodałem odpowiedź powyżej – AnT

Powiązane problemy