7

以下のように定義されている get_cpu_var マクロ

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

理解できないようです.変数ポインタ(アスタリスクに基づく)を返すのは一種の関数マクロであったか、それともある種の関数ポインタであると思います.私はそれに近いですか?誰かが私を啓発できますか?

4

1 に答える 1

16

({開始と終了の間に表示されるの})は、ステートメント式です。これは、GCC コンパイラの非標準機能であり、複合ステートメントを C 式に埋め込むことができます。このようなステートメント式の結果は、 内の最後の式ステートメント({})です。あなたの場合、それは&__get_cpu_var(var).

&演算子は__get_cpu_var(var)部分式の結果に適用されます。これ__get_cpu_varは、左辺値を返すことを意味します。これが実際に C である場合__get_cpu_var、C 言語の関数は左辺値を返すことができないため、これもマクロでなければなりません。

演算子は&ポインター (ステートメント式全体の結果) を生成し*、上記のマクロ定義の最初にある演算子によって逆参照されます。したがって、上記のマクロは本質的に*&__get_cpu_var(var)式と同等です。

*&__get_cpu_var(var)だけでなくとして実装されている理由を尋ねる人もいるかもしれません__get_cpu_var(var)。これは、 の結果の左辺値__get_cpu_var(var)を保持するためにそのように行われます。ステートメント式の結果は、最後のステートメントが左辺値であったとしても、常に右辺({})値です。結果の左辺値を保持するために、よく知られた*&トリックが使用されます。

このトリックは、GCC ステートメント式に限定されるものではありません。通常の日常的な C プログラミングで比較的頻繁に使用されます。たとえば、2 つの変数があるとします。

int a, b;

そして、セレクター変数に応じて、aまたは左辺値として返す式を書きたいとしますb(たとえば、それに割り当てたいとしましょう) 。素朴な試みは次のようになります42select

(select ? a : b) = 42;

C言語では、?:演算子はそのオペランドの左辺値を失うため、これは機能しません。結果は右辺値であり、代入できません。この状況では、*&トリックが助けになります

*(select ? &a : &b) = 42;

そして今、意図したとおりに動作します。

これがまさに、元の投稿者のマクロ定義に と の一見冗長なアプリケーションが含まれている方法と理由*です&。そのため、割り当てのどちらの側でも上記のget_cpu_varマクロを使用できます

something = get_cpu_var(something);
get_cpu_var(something) = something;

get_cpu_varそのトリックがなければ、右側でしか使用できません。

C++ 言語では、参照を使用して同じ効果が得られます。C では参照がないため、代わりにこのようなトリックを使用します。

于 2012-04-15T21:35:21.920 に答える