3

組み込みプロジェクトで、構造体を初期化するためのマクロを提供するライブラリを使用しています。これにより妥当なデフォルトが提供されますが、デフォルトは他のパラメータに依存します。後で値を初期化するとオーバーヘッドが発生するため、この指定された初期化子の 1 つ以上の値をオーバーライドしたいと考えています。

理想的には、サード パーティのコードを管理する必要があるため、すべてのマクロをコピー アンド ペーストしたくありません。ライブラリがデフォルトを変更した場合、私もそれをしたくありません。

指定された初期化子を組み合わせたりオーバーライドしたりする方法があるので、オーバーヘッドはありませんか? コードは C99 に準拠し、移植可能でなければなりません。

問題を示すサンプル コード:

#if SITUATION
#define LIBRARY_DEFAULTS \
{ \
  .field_a = 1, \
  .field_b = 2, \
  .field_c = 3 \
}
#else
#define LIBRARY_DEFAULTS \
{ \
  .field_a = 100, \
  .field_b = 200, \
  .field_c = 300, \
  .field_d = 400, \
  .field_e = 500 \
}
#endif

/* The following is what I want (or similar), but (of course) doesn't 
   work. */
// #define MY_DEFAULTS = LIBRARY_DEFAULTS + { .field_a = 100 }

int main(void) {
    /* The exact definition of something also depends on situation. */
    struct something library_thing = LIBRARY_DEFAULTS;

    /* This generates overhead, and I want to avoid this. It is certain
       that the field exists. */
    library_thing.field_a = 100;
}
4

2 に答える 2

1

考えられる解決策の 1 つを次に示します。最初にマクロから中括弧を削除します

#define LIBRARY_DEFAULTS .a=1, .b=2, .c=3

次に、デフォルトで問題ない変数については、マクロを中括弧で囲みます

struct something standard = { LIBRARY_DEFAULTS };

デフォルトを微調整する必要がある変数の場合、いくつかの初期化子を追加します

struct something tweaked = { LIBRARY_DEFAULTS, .a=100 };

なぜこれが機能するのですか?C 仕様のセクション 6.7.9 では、初期化リストでの指定子の使用について説明しており、同じ指定子を複数回指定することについて次のように述べています。

19 初期化は初期化子リストの順序で発生し、特定のサブオブジェクトに提供される各初期化子は、同じサブオブジェクトに対して以前にリストされた初期化子をオーバーライドします。151) 明示的に初期化されていないすべてのサブオブジェクトは、静的ストレージ期間を持つオブジェクトと同じように暗黙的に初期化されます。

そしてメモ151はこれを言います

151) オーバーライドされ、そのサブオブジェクトの初期化に使用されないサブオブジェクトの初期化子は、まったく評価されない可能性があります。

つまり、コンパイラは最後に指定された初期化子を使用する必要があり、オーバーヘッドなしでこのソリューションを実装できます

于 2016-02-20T18:55:39.913 に答える
1

外部構造でラップlibrary_thingし、外部構造の初期化子からオーバーライドを行うことができます。

#include <stdio.h>

struct foo {
    int a,b,c;
};

#define FOO_DEFAULTS { .a = 1, .b = 2, .c = 3 }

int main() {
    struct {
        struct foo x;
    } baz = {
        .x = FOO_DEFAULTS,
        .x.a = 4,
    };

    printf("%d\n", baz.x.a); // prints 4
}

実際、あなたもできる

.x = FOO_DEFAULTS,
.x = {.a = 4},

2 つのイニシャライザを実際に「マージ」する必要がある場合。

これは Clang (7.0.2) では正常にコンパイルされますが、.NET では警告が生成され-Winitializer-overridesます。生成されたコードを確認すると、構造体が で初期化されていることが確認される4, 2, 3ため、このトリックによる追加のオーバーヘッドはありません。

于 2016-02-20T18:43:03.583 に答える