【问题标题】:sizeof() of an array with random length具有随机长度的数组的 sizeof()
【发布时间】:2011-10-28 23:05:30
【问题描述】:

您能解释一下sizeof() 如何与随机长度数组一起工作吗?我以为数组上的sizeof() 是在编译过程中计算出来的,但是,随机长度的数组的大小似乎计算正确。

例子:

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

int main(){
    srand ( (unsigned)time ( NULL ) );
    int r = rand()%10;
    int arr[r]; //array with random length
    printf("r = %d size = %d\n",r, sizeof(arr)); //print the random number, array size
    return 0;
}

多次运行的输出:

r = 8 size = 32
r = 6 size = 24
r = 1 size = 4

编译器:gcc 4.4.3

【问题讨论】:

  • 我不知道int arr[r]; 是如何编译的。我认为堆栈中的数组需要在编译期间知道它们的大小。
  • @orip:看看 C99 的可变长度数组
  • 请注意,如果 rand()%10 恰好为 0,则行为未定义。 C 不支持零大小的数组(尽管 gcc 可能会这样做作为扩展)。

标签: c gcc random sizeof


【解决方案1】:

在 C99 中,可变大小数组的 sizeof 是在运行时计算的。来自 C99 草案 6.5.3.4/2:

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

【讨论】:

  • 你能给我解释更多细节吗,我对这个问题和你的回答不太了解。别跟我疯了。请。
  • 这里的重点是,在 C99 中,数组的大小不必在编译时指定。在这种情况下 sizeof 不是在编译时而是在运行时进行评估。
  • 这是否意味着一个数组的内存占用可能是数组大小加上额外的字节来存储它的大小?
  • @zoli2k:不。数组的大小(或更可能是元素的数量)将存储在内存中的某个位置,但这不计入数组大小的一部分。 sizeof arr 是元素数量乘以每个元素的大小。
  • @R..:你是对的。大小必须以某种方式可访问,但如果它从未使用过,则可以对其进行优化,并且如果它可以在编译时计算(即使它不是常量表达式),那么它不需要即使被使用,也可以存放在任何地方。关键是编译器可能会生成额外的数据,可能会占用内存,但不计入sizeof arr
【解决方案2】:

在您的代码中,arr 是一种特殊的数组:它是一个 VLA(可变长度数组)。

标准 (6.5.3.4) 中 sizeof 的段落说

如果操作数的类型是变长数组类型,则计算操作数

所以它不是编译时常量

【讨论】:

  • 语言律师的狡辩:C 标准的那部分实际上措辞有些糟糕。它说在表达式sizeof arr 中,表达式arr 被求值,但不清楚这意味着什么。 arr 是数组类型的表达式;它的值由它的元素的值组成。 (通常的指针衰减不会在这种情况下发生。)但是sizeof arr 当然不需要评估数组本身,它只需要确定它有多大,并且该信息来自类型,而不是从价值。但我不确定我会如何重新措辞。
  • @Keith,只是在这里大声思考,但是如果我有sizeof(arrparr[++i]),其中arrparr 类似于int (*int[6])[t]。在这种情况下,评估表达式会产生增加i 的副作用,或者如果它是空指针,则会调用未定义的行为(通常是段错误)。我刚试过这个。在这种情况下,CLANG 确实增加了i,但 GCC 4.1.2 没有。 CLANG 要么懒得去执行解引用,要么被优化掉(完全合法,因为只有一个空指针很重要,解引用是未定义的行为,因此什么都不做是合法的)。
  • 仔细看,我发现 CLANG 确实执行了取消引用,但它被优化了。另外我应该澄清任何无效指针都很重要,不仅仅是空指针,但在这种情况下编译器可能仍然什么都不做。
【解决方案3】:

在 C99 中,编译器足够聪明,可以知道在运行时调用 rand()

【讨论】:

  • 大声笑,而不是愚蠢的 C89 编译器 :)
  • 嗯...不是rand() 使数组特别。这个 sn-p:int k=42; int arr[k]; sizeof arr; 有一个和 OP 一样特别的数组。
  • @pmg:我没有关注你。似乎 rand() 生成一个随机数并用于数组大小。
  • 是的,但是 sizeof 运算符“起作用”是因为有两件事:数组是 VLA,编译器符合 C99。用 C89 编译器试试这个:const int k=42; int arr[k]; sizeof arr;
  • @Code Monkey:是的。这两种情况的共同点是数组长度是在运行时计算的,至少在原则上是这样。
【解决方案4】:

sizeof 与 C99 中引入的 VLA(可变长度数组)一起使用时,它们的大小在运行时而不是编译时进行评估。

查看关于该主题的非常好的参考资料here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-15
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 2012-10-21
    • 2015-11-12
    • 1970-01-01
    相关资源
    最近更新 更多