在结构数组的末尾需要空括号'{}'是什么?


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来表示字符串的结尾,该怎么办呢?只是猜测。
Eraklon

4
这是一些非标准的GCC扩展。因此,它很可能很少或根本没有文档...我只是读了所有文档,却找不到关于空的结构初始化器列表的任何信息。但是它会编译,除非您使用强制使用严格的ISO -pedantic
伦丁

9
无论如何,它是一个“前哨”值,一个将所有内容设置为零/ NULL的项目,以标记数组的结尾。
伦丁

CPython扩展模块中,哨兵也很常见。
MaxPowers

Answers:


38

这种特殊的变化是一部分的sysctl净:移除未使用的二进制代码的sysctl由Eric W.比德曼提交,改变的最后一个元件的初始化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
知道他们放弃标准C的理由,而希望在功能上等同于100%的GCC扩展,这将是很有趣的。它所做的只是防止代码在标准C编译器上编译。也就是说,据认为100%等效,因为gcc似乎没有记录此功能...这不是一个零长度的数组,它是一个空的初始化列表。
伦丁

@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之上的初始化列表的实际语法。必须至少有一个初始化程序。在这里解释:stackoverflow.com/questions/17589533/…。具体来说{ initializer-list }然后初始化列表:designation(opt) initializerinitializer-list , designation(opt) initializer
伦丁

2
@Lundin在这种特定情况下,不知道。但是gcc扩展在Linux内核中被广泛使用。
bobsburner

20

您可能熟悉零终止的字符串。ctl_table ip_ct_sysctl_table[]是一个以零结尾的数组,即最后一个数组条目具有全零成员。


1
因此,遍历数组时,您知道当eg procname为null或maxlen为零时,您已经到达末尾。
Paul Ogilvie

1
@PaulOgilvie:嗯,这个例子是不完整的。procname可能是char[100]在它的这种情况下"",不为空。但是,否则。
MSalters

13

在结构数组的末尾需要空括号'{}'是什么?

需要明确的是:不需要满足C语法要求的“结构数组末尾的空括号'{}'” 。

什么时候应该在结构数组的末尾使用空括号?

当代码需要一个哨兵值时

对于程序来说,使最终的数组元素全为零有时很有用 -当然可以检测到结尾。将需要来自应用程序的使用数组ctl_table ip_ct_sysctl_table[],而不是从C语言的需要。


9

它是数组末尾的一个零初始化元素,目的是将数组中的元素数量增加一。

考虑这个小演示:

#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
哈哈,不。想法是,到目前为止,没有人能够绝对确定地完全解释它。最接近的确定性声明就是,它{ }是一个初始化程序。但是为什么仍然不清楚。因此,就目前而言,这个词可能是一个好主意。:)
ryyker
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.