首页 > 解决方案 > gcc 的动态大小数组在声明后是否与标准数组有效相同?

问题描述

在标准 C 和 C++中,数组的地址是数组本身,并sizeof返回数组的大小,而不是指针。但是,gcc动态大小数组的扩展是否提供相同的保证?

我尝试了这个简单的代码

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char ** argv)
{
    char foo[200];
    char bar[atoi(argv[1])];
    char *wibble = foo;

    printf("%p, %p, %lu, %p, %p, %lu, %p, %p, %lu\n",
           foo, &foo, sizeof(foo), bar, &bar, sizeof(bar), wibble, &wibble, sizeof(wibble));

    return 0;
}

输出如我所愿,表明等价:

0x7ffc7dd132e0, 0x7ffc7dd132e0, 200, 0x7ffc7dd131e0, 0x7ffc7dd131e0, 200, 0x7ffc7dd132e0, 0x7ffc7dd132c8, 8

但是,这种等价性是否由 保证gcc?是否有任何时候使用动态大小而不是静态大小的数组会导致不同的程序行为?

※注意我感兴趣的是它是否有效,而不是如何更好地使用std::vector等等

标签: c++arraysgccvariable-length-array

解决方案


直接来自ISO C99 文档,第 80 页:

sizeof 运算符产生其操作数的大小(以字节为单位),它可以是表达式或带括号的类型名称。大小由操作数的类型决定。结果是一个整数。如果操作数的类型是变长数组类型,则计算操作数;否则,不计算操作数,结果是一个整数常量。

所以你的第一个问题的答案是它由 C99 标准保证,gcc 大概遵循。

至于是否有时它的行为会与静态大小的数组不同......如果你使用它们的时候不会。

虽然我在 ISO C99 中找不到这方面的记录,但 gcc 似乎总是将 VLA 放在堆栈上 - 这是有道理的,因为它本质上是一个 alloca(),并且打算在块的末尾超出范围. 明智地使用,动态大小的数组的行为方式与静态大小的数组的行为方式之间永远不会有任何区别。然而,疯狂使用,是的,可能存在剥削(或其他骇人听闻的)行为的极端极端情况,其中进行剥削的人可能很高兴发现您正在使用另一种。

无论如何,你可能会觉得使用任何你觉得舒服的人都会觉得舒服。通常,(出于不同合理性的一两个原因)程序员更喜欢 malloc 而不是堆栈分配。


推荐阅读