如果显式指定多维数组,为什么无法使用char [] [] = {{...},{...}}? [英] Why is char[][] = {{...}, {...}} not possible if explicitly given a multidimensional array?

查看:102
本文介绍了如果显式指定多维数组,为什么无法使用char [] [] = {{...},{...}}?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我经历了文章。我理解所解释的规则,但是我想知道到底是什么阻止了编译器在定义常量多维数组并直接使用给定类型的已知值对其进行初始化时接受以下语法:

  const int multi_arr1 [] [] = {{1,2,3},{1,2,3}}; // 为什么不? 
const int multi_arr2 [] [3] = {{1,2,3},{1,2,3}}; // OK

错误:声明 multi_arr1为多维数组时,除第一个
p>

阻止编译器向右看并意识到我们正在为每个子数组处理3个元素的情况,或者仅在程序员通过的情况下才可能返回错误,这是什么原因?
$ b每个子数组的元素数量不同,例如 {1,2,3},{1,2,3,4}

$ b

例如,当处理一维char数组时,编译器可以查看 = 右侧的字符串,这是有效的:

  const char str [] = Str; 

我想了解正在发生的事情,因此编译器无法推断出数组维数并进行计算自从现在以来,分配的大小在我看来似乎编译器已具有执行此操作所需的所有信息。我在这里缺少什么?

解决方案

要求编译器从初始化程序中推断内部尺寸将要求编译器在



该标准允许初始化的对象引用自己。例如:

  struct foo {struct foo * next;整数值} head = {& head,0}; 

这定义了一个链接列表的节点,该节点最初指向自身。 (大概以后会插入更多节点。)这是有效的,因为C 2011 [N1570] 6.2.1 7表示标识符 head 具有在完成后才开始的作用域声明者。 声明符是声明语法的一部分,其中包括标识符名称以及声明的数组,函数和/或指针部分(例如, f( int,float) * a [3] 是声明符,在诸如 float f(int,float ) int * a [3] )。



由于6.2.1如图7所示,程序员可以编写以下定义:

  void * p [] [1] = {{p [1]}, {p [0]}}; 

请考虑初始化程序 p [1] 。这是一个数组,因此它将自动转换为指向其第一个元素 p [1] [0] 的指针。编译器知道该地址,因为它知道 p [i] 是1 void * 的数组(对于任何值, i )。如果编译器不知道 p [i] 有多大,它将无法计算该地址。因此,如果C标准允许我们这样写:

  void * p [] [] = {{p [1]} ,{p [0]}}; 

然后,编译器将不得不继续扫描通过 p [1] ,因此它可以计算第二维给定的初始值设定项的数量(在这种情况下仅为一个,但是我们必须至少扫描到} 才能看到,可能还有更多),然后返回并计算 p [1] 的值。



该标准避免了强迫编译器执行这种多遍工作。要求编译器推断内部尺寸会违反此目标,因此标准不会这样做。



(实际上,我认为标准可能不需要编译器来做仅限于有限的前瞻,可能在标记化期间仅几个字符,而在语法分析时仅单个标记,但我不确定,有些东西直到链接时才知道值,例如 void(* p)(void)=& SomeFunction; ,但这些由链接器填充。)


I went through this article. I understand the rules explained but I am wondering what exactly blocks the compiler from accepting the following syntax when defining a constant multi-dimensional array and directly initializing it with known values of given type:

const int multi_arr1[][] = {{1,2,3}, {1,2,3}}; // why not?
const int multi_arr2[][3] = {{1,2,3}, {1,2,3}}; // OK

error: declaration of 'multi_arr1' as multidimensional array must have bounds
       for all dimensions except the first

What prevents the compiler from looking to the right and realizing that we are dealing with 3 elements for each "subarray" or possibly returning an error only for cases when the programmer passes e.g. a different number of elements for each subarray like {1,2,3}, {1,2,3,4}?

For example when dealing with a 1D char array the compiler can look at the string on the right hand side of = and this is valid:

const char str[] = "Str";

I would like to understand what's happening so that the compiler is not able to deduce the array dimensions and calculate the size for allocation since now it seems to me like the compiler has all the information needed to do so. What am I missing here?

解决方案

Requiring the compiler to infer inner dimensions from the initializers would require the compiler to work retroactively in a way the standard avoids.

The standard allows objects being initialized to refer to themselves. For example:

struct foo { struct foo *next; int value; } head = { &head, 0 };

This defines a node of a linked list that points to itself initially. (Presumably, more nodes would be inserted later.) This is valid because C 2011 [N1570] 6.2.1 7 says the identifier head "has scope that begins just after the completion of its declarator." A declarator is the part of the grammar of a declaration that includes the identifier name along with the array, function, and/or pointer parts of the declaration (for example, f(int, float) and *a[3] are declarators, in a declarations such as float f(int, float) or int *a[3]).

Because of 6.2.1 7, a programmer could write this definition:

void *p[][1] = { { p[1] }, { p[0] } };

Consider the initializer p[1]. This is an array, so it is automatically converted to a pointer to its first element, p[1][0]. The compiler knows that address because it knows p[i] is an array of 1 void * (for any value of i). If the compiler did not know how big p[i] was, it could not calculate this address. So, if the C standard allowed us to write:

void *p[][] = { { p[1] }, { p[0] } };

then the compiler would have to continue scanning past p[1] so it can count the number of initializers given for the second dimension (just one in this case, but we have to scan at least to the } to see that, and it could be many more), then go back and calculate the value of p[1].

The standard avoids forcing compilers to do this sort of multiple-pass work. Requiring compilers to infer the inner dimensions would violate this goal, so the standard does not do it.

(In fact, I think the standard might not require the compiler to do any more than a finite amount of look-ahead, possibly just a few characters during tokenization and a single token while parsing the grammar, but I am not sure. Some things have values not known until link time, such as void (*p)(void) = &SomeFunction;, but those are filled in by the linker.)

这篇关于如果显式指定多维数组,为什么无法使用char [] [] = {{...},{...}}?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆