问题描述
我刚刚发现我可以使用 sizeof() 来初始化数组,但不能使用 strlen(),这是为什么呢?
char str[] = " @@ Aab,~bccdD>> e",str2[sizeof(str)]={-1};
如果我使用 strlen(),它会给我这个错误,但 sizeof 的返回值不应该也是一个变量吗?
错误:可能无法初始化可变大小的对象 char str[] = " @@ Aab,str2[strlen(str)]={-1};
解决方法
sizeof
是一个运算符,而不是一个函数,并且有一个例外,它的值在编译时是已知的。当用作数组大小时,它类似于使用像 10
这样的常量表达式。
由于 strlen
是一个函数,它直到运行时才会被评估。从 C99 开始,您可以声明一个以运行时值作为大小的数组 - 这些称为可变长度数组。虽然有用,但 VLA 有一些限制,其中之一是您不能使用初始化程序声明它们。您必须使用 memset
或类似的东西设置初始值:
char str[] = " @@ Aab,~bccdD>> e",str2[sizeof(str)];
memset( str2,-1,sizeof str2 );
在运行时评估 sizeof
的一个例外是在 VLA 上使用它时,因为 VLA 的大小直到运行时才确定。
C 2018 6.7.9 说一个可变长度数组可能没有被初始化:
要初始化的实体类型应为未知大小的数组或非变长数组类型的完整对象类型。
C 2018 6.7.6.2 4 表示如果数组声明的大小不是整数常量表达式,则它是可变长度数组:
... 如果大小为整型常量表达式且元素类型具有已知常量大小,则该数组类型不是变长数组类型;否则,数组类型为变长数组类型...
常量表达式受 C 2018 6.6 3 限制:
常量表达式不应包含赋值、递增、递减、函数调用或逗号运算符,除非它们包含在未计算的子表达式中。
因此,使用 strlen(str)
使数组成为无法初始化的可变长度数组。我不知道这个禁令的确切动机,但我会注意到,允许可变长度数组的初始化可能需要编译器生成比 C 定义的典型代码更多的代码。
这足以解释错误消息,但我会注意到整数常量表达式受到 C 2018 6.6 4 的进一步限制:
整数常量表达式应具有整数类型,并且只能具有整数常量、枚举常量、字符常量、结果为整数常量的 sizeof
表达式、{{1} } 表达式和作为转换的直接操作数的浮动常量。整数常量表达式中的强制转换运算符只能将算术类型转换为整数类型,除非作为 _Alignof
或 sizeof
运算符的操作数的一部分。