構造体の配列の最後に空の中括弧 '{}'が必要なのは何ですか?


59

Linuxカーネルで コードをいくつかヒットしました。

static struct ctl_table ip_ct_sysctl_table[] = {
    {
        .procname   = "ip_conntrack_max",
        .maxlen     = sizeof(int),
        .mode       = 0644,
        .proc_handler   = proc_dointvec,
    },
    // ...
    {
        .procname   = "ip_conntrack_log_invalid",
        .maxlen     = sizeof(unsigned int),
        .mode       = 0644,
        .proc_handler   = proc_dointvec_minmax,
        .extra1     = &log_invalid_proto_min,
        .extra2     = &log_invalid_proto_max,
    },
    { }
};

ここで、構造体の配列はで終わり{ }ます。どのような目的で追加されましたか?
ちなみに、このコードの少し上には、構造体の別の配列がありますが、最後に空のブレースがありません。

構造体の配列の最後に空のブレースを使用する必要があるのはいつですか?


1
うーん、0のように配列の終わりを示すために追加された場合はどうなりますか?推測するだけです。
エラクロン

4
これは非標準のGCC拡張機能です。そのため、ほとんどまたはまったくドキュメントが付属していない可能性があります...私はすべてのドキュメントを読んだだけで、空のstruct初期化子リストについては何も見つかりません。ただし、で厳密なISOを強制しない限り、コンパイルされます-pedantic
ランディン

9
とにかく、それは「センチネル」値であり、配列の終わりを示すためにすべてがゼロ/ NULLに設定された項目です。
ランディン

センチネルはCPython拡張モジュールでも一般的です。
MaxPowers

回答:


38

この特定の変更は、の一部であったのsysctlネット:未使用のsysctlバイナリコードを削除する最後の要素の初期変化、エリックW. Biedermanによってコミットip_ct_sysctl_tableからアレイ{0}{}(および実行多くの他の配列の初期化と同様の変更を)。

{0}パターンは、はるかに長いけれども出回っているようだ、との両方{0}又は{}最終要素初期化が明示的と呼ばれる(Linuxのソースコードで)一般的でありTerminating entry、それはそれらの長さを知らずにこれらの配列を消費することを可能にするパターンの存在がそうであるように、ゼロで初期化された終了エントリにヒットしたときに消費を終了します。たとえばsound/aoa/fabrics/snd-aoa-fabric-layout.c、ゼロ初期化の目的で同様の配列がコメントで明示的に言及されている場合でも、たとえば:

static struct codec_connection toonie_connections[] = {
  {
      .connected = CC_SPEAKERS | CC_HEADPHONE,
      .codec_bit = 0,
  },
  {} /* terminate array by .connected == 0 */
};

11
機能の点で100%同等のGCC拡張を支持して標準Cを削除する理由を知ることは興味深いでしょう。それが行うのは、コードが標準のCコンパイラでコンパイルできないようにすることだけです。つまり、gccはこの機能を文書化していないため、100%等価であると考えられます...これは長さゼロの配列ではなく、空の初期化リストです。
ランディン

@Lundinはint arr[] = {}(GNU空のイニシャライザ拡張機能を使用している場合)空の配列にはなりません。すなわち、存在の大きarr0
dfri

1
@Lundin:ただし、cppreferenceページは、それを可能にするISO / IEC 9899:2011の文言と矛盾しています(§6.7.9(21))。イニシャライザは、アグリゲートのメンバーよりも間違いなく「少ない」ものではありません。だから、奇妙なコンパイラの拡張機能ではないですが、合法的なC.
デイモン

2
@Damonこれは有効なCではなく、よく知られています... gcc -pedantic-errorsでコンパイルします。理由を理解するには、6.7.9の上部にある初期化リストの実際の構文を読む必要があります。少なくとも1つの初期化子が必要です。ここで説明:stackoverflow.com/questions/17589533/…。具体的には{ initializer-list }、初期化子リスト:designation(opt) initializerまたはinitializer-list , designation(opt) initializer
Lundin

2
@Lundinこの特定のインスタンスでは、わかりません。しかし、gcc拡張機能はLinuxカーネルで広く使用されています。
ボブスバーナー

20

あなたはおそらくゼロで終了する文字列に精通しています。ctl_table ip_ct_sysctl_table[]ゼロで終了する配列です。つまり、最後の配列エントリにはすべてゼロのメンバーがあります。


1
したがって、配列をprocname調べると、eg がnullまたはmaxlen0のときに最後に到達したことがわかります。
Paul Ogilvie

1
@PaulOgilvie:まあ、例は不完全です。procnamechar[100]場合""はnullではなくです。しかし、そうでなければそうです。
MSalters

13

構造体の配列の最後に空の中括弧 '{}'が必要なのは何ですか?

明確にするために、「構造体の配列の最後にある空のブレース '{}'」は、C構文の要件を満たす必要はありません。

構造体の配列の最後に空のブレースを使用する必要があるのはいつですか?

コードがセンチネル値を必要とする場合

それは時々ある便利な終わりを検出するために、確かに-プログラムがすべてゼロの最後の配列要素を持っています。必要性は、アレイのアプリケーションの使用から来てctl_table ip_ct_sysctl_table[]いないC言語の必要性から、。


9

配列の要素数を1つ増やすために、配列の最後にある1つのゼロ初期化要素です。

この小さなデモを考えてみましょう:

#include <stdio.h>

struct Test
{
  int x;
  int y;
} arr[] =
{
    {1,2},
    {3,4},
//  {}
};

int main(void) {
    printf("%zu\n", sizeof(arr) / sizeof(arr[0]));
    return 0;
}

配列初期化リストの最後にあるarrコメントを解除すると、配列のサイズが変わります{}

出力:

あり // {}(配列には2つの要素があります)

2

あり {}(配列には3つの要素があります)

3

詳細説明:

ip_ct_sysctl_table配列は、ここでしかある一つの場所、で使用されます。

in->ctl_table = kmemdup(ip_ct_sysctl_table,
                sizeof(ip_ct_sysctl_table),
                GFP_KERNEL);

エクストラ{}は合計サイズを増やしますip_ct_sysctl_table


1
それは「配列の要素数を増やすため」ではなく、配列の終わりを知らせるためです。
Paul Ogilvie

6
笑 これまでのところ、誰も完全に確実にそれを完全に説明することはできなかったという考えです。確実性に最も近いステートメントは、単にが{ }初期化子であるということです。しかし、その理由はまだ不明です。このように、今とにかくために、言葉はおそらく、おそらく良いアイデアです。:)
ライカー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.