6

私はC/Objective-Cでアプリケーションを開発しています(C ++はありません、私はすでにそこに解決策を持っています)、そして私は興味深いユースケースに出くわしました。

clangはネストされた関数をサポートしていないため、私の元のアプローチは機能しません。

#define CREATE_STATIC_VAR(Type, Name, Dflt) static Type Name; __attribute__((constructor)) void static_ ## Type ## _ ## Name ## _init_var(void) { /* loading code here */ }

このコードはGCCで正常にコンパイルされますが、clangはネストされた関数をサポートしていないため、コンパイルエラーが発生します。

期待される ';' 宣言の終わりに。

だから、私は関数内の変数でClangのために働く解決策を見つけました:

#define CREATE_STATIC_VAR_LOCAL(Type, Name, Dflt) static Type Name; ^{ /* loading code here */ }(); // anonymous block usage

ただし、マクロ連結を利用して、状況に適した連結を選択する方法があるかどうか疑問に思いました。たとえば、次のようになります。

#define CREATE_STATIC_VAR_GLOBAL(Type, Name, Dflt) static Type Name; __attribute__((constructor)) void static_ ## Type ## _ ## Name ## _init_var(void) { /* loading code here */ }
#define CREATE_STATIC_VAR_LOCAL(Type, Name, Dflt) static Type Name; ^{ /* loading code here */ }(); // anonymous block usage

#define SCOPE_CHOOSER LOCAL || GLOBAL
#define CREATE_STATIC_VAR(Type, Name, DFLT) CREATE_STATIC_VAR_ ## SCOPE_CHOOSER(Type, Name, Dflt)

明らかに、最終的な実装は正確にそれである必要はありませんが、同様のもので十分です。

で使用しようとしまし__builtin_constant_pたが、コンパイル時定数ではないため、機能しませんでした__func____func__

私も使用しようとし__builtin_choose_exprましたが、グローバルスコープでは機能しないようです。

ドキュメントに欠けているものは他にありますか?このようなことはかなり簡単なことのように思えますが、それでも私には理解できないようです。

注:マクロ連結を使用する代わりに、単純に入力できることは承知していますが、これはコンパイラーの限界を押し広げようとしている私CREATE_STATIC_VAR_GLOBALです。CREATE_STATIC_VAR_LOCALまた、C ++を使用してこれをすぐに解決できることも認識していますが、それはここでの私の目標ではありません。

4

2 に答える 2

3
#define SCOPE_CHOOSER LOCAL || GLOBAL
#define CREATE_STATIC_VAR(Type, Name, DFLT) CREATE_STATIC_VAR_ ## SCOPE_CHOOSER(Type, Name, Dflt)

ここでの最大の難しさは、Cプリプロセッサがテキスト置換によって機能することです。したがって、SCOPE_CHOOSERやりたいことを実行する方法を理解したとしても、次のようなマクロ展開になってしまいます。

CREATE_STATIC_VAR_LOCAL || GLOBAL(Type, Name, Dflt);

置換中にプリプロセッサを「定数畳み込み」マクロ展開にする方法はありません。物事が「折りたたまれる」のは、それらが#if表現に現れるときだけです。したがって、あなたの唯一の望み(モジュロわずかな手振り)は、関数の内側と外側の両方で機能する単一の構造を見つけることです。

ここで最終的な目標について詳しく説明していただけますか?変数の初期値をでロードできるとは思いません__attribute__((constructor))が、関数本体が最初に入力されたときに初期値をロードする方法があるかもしれません...またはコンパイル時にこれらの変数のすべてのアドレスをグローバルリストに登録します-時間とそのリストをトラバースする単一の__attribute__((constructor))関数を持っています...またはそれらのアプローチのいくつかのミッシュマッシュ。具体的なアイデアはありませんが、もっと情報を提供していただければ、何かが浮かび上がるかもしれません。

編集: これはプリプロセッサのトリックではないので、これも役に立たないと思いますが、関数スコープで0、グローバルスコープで1と評価される定数式を次に示します。

#define AT_GLOBAL_SCOPE __builtin_types_compatible_p(const char (*)[1], __typeof__(&__func__))

ただし、「拡張」ではなく「評価」と言ったことに注意してください。これらの構成はコンパイル時であり、前処理時ではありません。

于 2012-08-30T18:04:01.203 に答える
0

@Qxuuplusoneの回答に触発されました。

の推奨マクロは(GCCで)実際に機能しますが、コンパイラ警告が発生します(ここでのテストで作成されているため、 Diagnostic PragmaAT_GLOBAL_SCOPEで消音できないと確信しています)。pedwarn

オンにしない限り-w、これらの警告が常に表示され、心の奥底に、自分がしていることを何でもしてはいけないという恐ろしい気持ちがあります。

幸いなことに、これらの長引く疑問を沈黙させることができる解決策があります。その他のビルトインのセクションには__builtin_FUNCTION、この非常に興味深い説明があります(私の強調):

この関数は__FUNCTION__シンボルと同等であり、組み込みが呼び出された関数の名前を指すアドレス定数を返します。呼び出しが関数スコープにない場合は空の文字列を返します。

少なくともGCCのバージョン8.3では、次のことができます。

#define AT_GLOBAL_SCOPE (__builtin_FUNCTION()[0] == '\0')

これでも元の質問には答えられない可能性がありますが、GCCがこれも警告を表示すると判断するまで(意図的に設計されていないように見えます)、マクロを使用して疑わしいことを続けても、警告は表示されません。それは悪い考えです。

于 2021-10-13T09:09:23.963 に答える