为什么使用带有作为大小变量的字符数组进行编译?

时间:2019-05-31 17:02:30

标签: c++

在使用模板时,我遇到了一个有趣的现象,即数组并定义了它的大小,我认为这在C ++中是不允许的。

我使用了一个全局变量来定义main()内部数组的大小,由于某种原因,它起作用了(请参见下面的代码)

1)为什么还要编译?我以为只有constexpr可以用于数组大小

2)假设上面的方法是有效的,即使sz = 8(明显小于字符串的大小),它仍然无法解释为什么有效

3)为什么我们会收到奇怪的“ @”和“?”。我尝试了不同的字符串组合,例如,仅数字字符(“ 123456789”)并没有出现。

感谢任何帮助。谢谢。

这是我的代码

#include <iostream>
#include <cstring>


using namespace std;


int sz = 8;

int main()
{
    const char temp[sz] = "123456abc"; //9 characters + 1 null?

    cout << temp << endl;

    return 0;
}

输出:

123456ab。 @

1 个答案:

答案 0 :(得分:1)

  

1)为什么还要编译?我以为只有constexpr可以用于数组大小

提问者是正确的,Variable Length Arrays(VLA)不是标准C ++。 g ++编译器通过扩展支持VLA。怎么会这样?只要符合标准要求的行为,编译器开发人员就可以添加几乎任何所需的内容。开发人员应自行记录行为。

  

2)假设上面的方法是有效的,即使sz = 8(明显小于字符串的大小),它仍然无法解释为什么有效

通常,如果使用大于数组大小的值初始化数组,则g ++会发出错误。我必须与文档进行确认,以查看在这种情况下C ++ Standard是否需要错误。这似乎是发生错误的好地方,但是我不记得是否需要进行错误处理。

在这种情况下,VLA扩展似乎具有副作用,从而消除了g ++通常为尝试过度填充数组而吐出的错误。这很有意义,因为在通常情况下,编译器在编译时不知道数组的大小,因此无法执行测试。没有测试,没有错误。

由于不支持VLA,因此C ++标准均未涵盖这些内容。

快速浏览允许使用VLA的C标准并没有为这种情况提供任何指导。 C初始化VLA的规则非常简单:您不能。编译器不知道数组在编译时的大小,因此无法初始化。字符串文字可能会有例外,但我还没有找到。

我也没有在GCC文档中找到关于该行为的良好描述。

clang produces the error I expect基于我对C标准的理解:错误:可变大小的对象可能未初始化

附录:可能应该先检查堆栈溢出并为自己节省很多时间:Initializing variable length array

  

3)为什么我们会收到奇怪的“ @”和“?”。我尝试了不同的字符串组合,例如,仅数字字符(“ 123456789”)并没有出现。

似乎正在发生的事情,并且由于这都不是标准的,因此我没有引号来支持它,是将字符串文字复制到VLA中,达到VLA的大小。超出VLA末尾的文字部分会被静默丢弃。这包括空终止符,在打印未终止的char数组时,行为是不确定的。

解决方案:

尽可能坚持标准化行为。主要的编译器都有警告您非标准代码的选项。 -pedantic与使用gcc选项的编译器一起使用,/permissive-与Visual Studio的最新版本一起使用。当被迫超出标准时,请查阅编译器文档或实施者本身以了解是否存在粘滞或未记录的比特。

如果您没有很好的答案,请尝试找到其他路径。