C 中数组的平面列表初始值设定项

问题描述 投票:0回答:2

一个典型的二维数组初始化是这样的:

int arr[3][5] = { {0,1,2,3,4}, {5,6,7,8,9}, {10,11,12,13,14} };

我们被教导这是初始化数组的“正确方法”。 但它真的“正确”就好像使用单个平面列表复合文字是不正确的吗? 事实证明这也是可编译的:

int arr[3][5] = { 0,1,2,3,4, 5,6,7,8,9, 10,11,12,13,14 };

(这可能与所有数组元素都放置在连续内存中这一事实有关。)

就词法而言,两种代码在 GCC 中编译并看似产生相同的结果。 前者显然在可读性方面胜出,除了在某些情况下它会使情况变得更糟。而且我不明白为什么我们不能像我刚才那样用空格分隔“维度”。 我对这对编译器究竟意味着什么特别感兴趣。 我无法让它产生只能依赖于大括号存在的警告。可以通过任何一种方式检测过量元素。如果唯一的问题出在编译器的诊断中,那么我想知道只有在存在大括号时才会触发哪些警告/错误。

arrays c multidimensional-array initialization compound-literals
2个回答
1
投票

您可以自由使用格式来提高人类的可读性,例如:

   int a[3][5] = {
       0,1,2,3,4,
       5,6,7,8,9,10,
       11,12,13,14,15
   };

但是,对于没有任何规则来处理特殊空格的编译器来说,这并不重要。一个分隔符。

编译器需要大括号来了解你的意图:

   int a[3][5] = {
       {0,1,2,3,4},
       {5,6,7,8,9,10},
       {11,12,13,14,15}
   };

知道这一点,编译器能够在出现问题时发出警告:

   int a[3][5] = {
       {0,1,2,3,4},
       {5,6,7,8,9,10,11},  // <--- excess elements in array initializer
       {12,13,14,15}
   };

或正确放置初始化常量:

   int a[3][5] = {
       {0,1,2,3,4},
       {5,6,7},    // Use default value for remaining elements
       {11,12,13,14,15}
   };

顺便说一句,GCC(v 11.2.0 with

-Wall -Wextra
)不会对空括号发出任何警告:

   int a[3][5] = {
       {0,1,2,3,4},
       {},    // Use default value for entire row
       {11,12,13,14,15}
   };

C 语言和现代编译器为我们提供了很多帮助,但更多的是自由,包括编写混乱和难以维护的代码的自由。 “正确”的做事方式(无论是通过教学还是公司编码标准定义的)是我们作为语言用户为自己设定的规则,以使代码易于理解和健壮。如果您为自己编写代码,则可以自由定义自己的“正确”做事方式。


0
投票

花括号允许编译器更准确地解释代码,以检测人为错误,或允许更短的代码。

例如:

static int arr[3][5] = { {0,1,2,3}, {5,6}, {10,11,12,13} };

是正确的,并允许编码人员利用默认值编写更短的代码。

其他例子:

static int arr[3][5] = { {0,1,2,3,4,5}, {6,7,8,9}, {10,11,12,13,14} };

编译器会检测到一个错误。因为内存中还有 15 个 int,这真的是一个错误吗?是的海事组织。 C 是一种高级语言,接近机器是的,但它不是汇编:在数组中使用多个维度不仅仅是内存大小分配。

编译器也不完美:

static int array_4[3][5] = { {0,1,2,3,4}, { }, {10,11,12,13,14} };

这里 Visual C++ 检测到一个错误,因为

{ }
为空。但 IMO 这种语法应该是可以接受的。

© www.soinside.com 2019 - 2024. All rights reserved.