用于在初始化期间表示数组大小的有效和无效语法

Tho*_*hor 14 c arrays

我目前正在研究c阵列,并且对在初始化期间能够和不能用于表示阵列大小的内容感到困惑.

我是正确的假设

#define SIZE 5 
Run Code Online (Sandbox Code Playgroud)

const int SIZE = 5; 
Run Code Online (Sandbox Code Playgroud)

从根本上是不同的?

他们有区别,一个让我感到困惑的特殊例子

#define SIZE 5
int arr[SIZE] = {11, 22, 33, 44, 55}; 
Run Code Online (Sandbox Code Playgroud)

是有效的语法,但是

const int SIZE = 5;
int arr[SIZE] = {11, 22, 33, 44, 55};
Run Code Online (Sandbox Code Playgroud)

是无效的语法.虽然有趣,

const int SIZE = 5;
int arr[SIZE];
Run Code Online (Sandbox Code Playgroud)

是有效的语法.

特定语法是有效还是无效的背后的逻辑是什么?

P.P*_*.P. 11

我是正确的假设

#define SIZE 5

const int SIZE = 5;

从根本上是不同的?

是的,你是对的.

#define只是一个文本替代品.基本上,C预处理器在编译过程(处理阶段)中为您进行"查找和替换".然而,const合格的对象意味着"存储在这个位置的东西不能改变" - 大致相当于说它是"只读".


#define SIZE 5
int arr [SIZE] = {11,22,33,44,55};

是有效的语法.

这完全等同于写作:

int arr[5] = {11, 22, 33, 44, 55}; 
Run Code Online (Sandbox Code Playgroud)

你自己.编译器只是在您使用时为您执行替换作业define.


const int SIZE = 5;

int arr [SIZE] = {11,22,33,44,55};

是无效的语法.

这是无效的,但原因可能不止一个.如果arr具有静态存储持续时间(即,在arr整个程序执行期间对象处于活动状态)则它无效.因为C要求具有静态存储持续时间的数组对象的大小为常量表达式:

如果size是一个整型常量表达式,并且元素类型具有已知的常量大小,则数组类型不是可变长度数组类型; 否则,数组类型是可变长度数组类型.

因此,以下程序无效:

const int SIZE = 5;
int arr[SIZE] = {11, 22, 33, 44, 55};
int main(void)
{
}
Run Code Online (Sandbox Code Playgroud)

因为SIZE它不符合C中的"常量表达式".请注意,这在C++中完全有效,其中SIZE有资格作为常量表达式(这里两种语言不同).

另一个原因是C标准不允许初始化可变长度数组.如果您在函数中有定义,例如:

要初始化的实体的类型应为未知大小的数组或不是可变长度数组类型的完整对象类型.

因此,如果您没有初始化程序,那么它将变为有效:

int main(void)
{
    const int SIZE = 5;
    int arr[SIZE];  /* This is OK */
}
Run Code Online (Sandbox Code Playgroud)

同样,你也可以不用这样做const:

int main(void)
{
    int SIZE = 5;
    int arr[SIZE]; /* Thi is OK too. */
}
Run Code Online (Sandbox Code Playgroud)

在上述两个片段中,arr只是一个可变长度的数组.

虽然有趣,

const int SIZE = 5; int arr [SIZE];

是有效的语法.

只有在函数内部(如上所述)它才有效 - 它是一个VLA.但如果你使它具有静态存储持续时间,例如:

const int SIZE = 5;
int arr[SIZE]; /* arr has static storage duration just as
                 all objects defined at file scope */

int main(void)
{
}
Run Code Online (Sandbox Code Playgroud)

它是无效的,因为如上所述,SIZE它不是C中的"常量表达式".

同样的,

int main(void)
{
    const int SIZE = 5;
    static int arr[SIZE]; /* arr has static storage duration */
}
Run Code Online (Sandbox Code Playgroud)

arr由于arr具有静态存储持续时间,因此尽管属于函数内部,但由于同样的原因是无效的.


但是,如果你有:

enum {SIZE = 5};
int arr[SIZE] = {11, 22, 33, 44, 55};
 int arr2[SIZE]; /* Valid without initializer too. */

int main()
{
}
Run Code Online (Sandbox Code Playgroud)

它是有效的.为什么?因为枚举常量在C中符合"常量表达式".


use*_*738 8

标准解释为6.7.9p3

要初始化的实体的类型应为未知大小的数组或不是可变长度数组类型的完整对象类型.

在第二种情况下,它是VLA,但在第一种情况下它不是.预处理后,它就像int arr[5] = {..}.

在VLA情况下,编译器在定义VLA时不知道VLA的大小,因此无法检查初始化程序的有效性.这就是为什么不允许这种初始化的原因.

顺便说一句,使用const并不意味着它是一个编译时常量 - 它只是意味着它不能被改变.

同样从6.7.6.2p4开始,对于何时是VLA以及何时不是VLA有明确的区别: -

...如果size是一个整型常量表达式,并且元素类型具有已知的常量大小,则数组类型不是可变长度数组类型; 否则,数组类型是可变长度数组类型.


hac*_*cks 6

#define SIZE 5定义SIZE一个整数常量表达式.虽然const int SIZE = 5;定义SIZE变量表达式,但不得修改其值.const限定符不会使它成为整数常量表达式(在c ++中它会这样做).

标准说

n1570-§6.7.6.2(p4):

[...]如果size是一个整型常量表达式,并且元素类型具有已知的常量大小,则数组类型不是可变长度数组类型; 否则,数组类型是可变长度数组类型.[...]

当你这样做

#define SIZE 5
int arr[SIZE] = {11, 22, 33, 44, 55}; 
Run Code Online (Sandbox Code Playgroud)

它声明arr为一个不是可变长度数组(VLA)的数组.而

const int SIZE = 5;
int arr[SIZE];
Run Code Online (Sandbox Code Playgroud)

声明arr为可变长度数组,因为SIZE它不是整数常量表达式,而是变量表达式.但是同样的声明因初始化列表而失败,那是因为对VLA有限制是因为它们无法使用列表初始化器进行初始化.

§6.7.9(第2页和第3页):

初始化程序不应尝试为未初始化的实体中包含的对象提供值.

要初始化的实体的类型应为未知大小的数组或不是可变长度数组类型的完整对象类型.