声明后,gcc 的动态大小数组是否与标准数组有效相同?

Are gcc's dynamically-sized arrays effectively identical to standard arrays after declaration?

本文关键字:数组 是否 标准 有效 小数 gcc 动态 声明      更新时间:2023-10-16

在标准 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, %lun",
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等更好地编写它

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

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

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

至于有时候它的行为会与静态大小的数组不同......如果您理智地使用它们,则不会。

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

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