【问题标题】:Declaring array size of auto variable from input argument从输入参数声明自动变量的数组大小
【发布时间】:2009-09-25 00:41:27
【问题描述】:

我一直在运行 gcc 4.3.3 的 Ubuntu 9.04 系统上使用堆栈,并将 randomize_va_space 内核变量设置为 0(/proc/sys/kernel/randomize_va_space)

如果我在一个函数中声明一个自动变量,该函数是一个数组,其大小由输入决定,那么该数组是如何在堆栈上分配的?

函数看起来像这样 -

int fun(int i) {
    char a[i];
    char *ptr;

    printf("a - %p ptr - %p\n", a, &ptr);
    printf("Difference - %ld\n", ((unsigned long)&ptr - (unsigned long)a);
    printf("sizeof(a) - %d\n\n", sizeof(a));
}

sizeof 运算符在传递数组 a 时返回预期大小(甚至是 -1)所以我想知道为什么数组在堆栈上占用这么多空间,其次为什么 sizeof() 返回 -1?

输出看起来像这样 -

a - 0xbffff4c0 ptr - 0xbffff4fc
Difference - 60
sizeof(a) - -1

a - 0xbffff4c0 ptr - 0xbffff4fc
Difference - 60
sizeof(a) - 0

a - 0xbffff4c0 ptr - 0xbffff4fc
Difference - 60
sizeof(a) - 1

a - 0xbffff4b0 ptr - 0xbffff4fc
Difference - 76
sizeof(a) - 2

a - 0xbffff4b0 ptr - 0xbffff4fc
Difference - 76
sizeof(a) - 3

a - 0xbffff4b0 ptr - 0xbffff4fc
Difference - 76
sizeof(a) - 4

【问题讨论】:

  • 这不应该编译。您只能在堆栈上声明常量大小的数组。通常你需要做 char *a = new char[i];
  • 我也是这么想的,但是编译运行都很好。
  • 我想知道您使用的是什么编译器...:P
  • 只要运行 'gcc -S prog.c' 你就会看到。

标签: c stack


【解决方案1】:

可变长度自动数组在 C99 中被引入到 C 中。

数组是通过数组大小调整堆栈指针来分配的,就像一个普通的自动变量一样——唯一的区别是堆栈指针调整的大小和a与帧指针的偏移量不是常量可以在编译时计算 - 它们必须在运行时计算。

同样,sizeof 在可变长度数组上正常工作,当它应用于这样的数组时,它也无法在编译时计算。输入范围时必须记住a分配的大小。

正是这种管理信息——可变长度自动数组的数量、大小和偏移量——被保存在堆栈中aptr 之间的额外空间中。那里可能还有一个额外的保存帧指针 - 你真的必须深入研究源代码才能让你的编译器找到。

哦,您从sizeof 看到-1 的原因是您使用%d 说明符错误地打印了它 - 使用%zu 表示size_t

【讨论】:

    【解决方案2】:

    支持 C99 变量数组语义的编译器应该编译它(尽管我对 var 数组并没有太多经验)。

    对于每个迭代,i 的值是多少?这将有助于解释为什么 aizeof() 在某些情况下会返回 -1

    根据这个页面:

    可变长度数组在主线 GCC 中工作,但根据:

    它们在 GCC 4.3 中被破坏。这可能解释了您在使用 sizeof() 时遇到的问题。

    【讨论】:

    • sizeof() 返回的值是作为“i”传递给函数的值。
    • C99 标准规定,每次对数组声明中的表达式求值时,它的值都应大于 0。当您传入 -1 或 0 时,您将获得未定义的行为 - 在这种情况下你得到一个 sizeof() == -1 或 0。至于为什么即使对于 i 的小值,数组似乎也占用了这么多空间 - 我不知道(记住,GCC C99 状态文档说支持被破坏了)。
    【解决方案3】:

    我很惊讶这个编译。除非编译器知道要分配多少,否则编译器无法在编译时在堆栈上分配内存。当您使用“new”或“malloc”进行分配时,内存是在堆外分配的。这是我编译时得到的:

    alloc.c(2):错误 C2057:预期的常量表达式
    alloc.c(2) : 错误 C2466: 无法分配常量大小为 0 的数组
    alloc.c(2) : 错误 C2133: 'a' : 未知大小
    alloc.c(7) : 警告 C4034: sizeof 返回 0

    我认为剩下的问题没有实际意义。

    【讨论】:

    • 编译器当然可以在堆栈上分配内存,其大小在运行时确定——这就是 alloca() 在支持它的编译器上所做的。
    猜你喜欢
    • 2011-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多