【问题标题】:Why this 'sizeof()' return is 0 bytes in C? [duplicate]为什么这个'sizeof()'返回在C中是0字节? [复制]
【发布时间】:2021-07-02 10:53:19
【问题描述】:

我的问题是关于sizeof 和内存分配。当我学习 C 和测试类型值时,我尝试了以下代码:

#include <stdio.h>

int main(void) {
char vec[0];
vec[0] = 1;
printf("\n SIZEOF: %li", sizeof(vec));
printf("\n VEC[0]: %li", vec[0]);
}

输出是:

> SIZEOF: 0

> VEC[0]: 1

为什么“vec[0]”的大小为“0 字节”,即使我添加了值“vec[0] = 1”? (如果我不添加这个值,只需声明向量“char vec[0] or int vec[0]”输出相同)。

Ricxk。你的时间。

【问题讨论】:

  • 你声明了char vec[0]; ... 为什么它会有一个sizeof() 不是零? vec[0] = 1; 是未定义的行为,因为您在数组外部写入。
  • 编译器应该对你大喊大叫 char vec[0]; - 数组不能声明为 0 大小。
  • 在编译时启用所有警告可能是个好主意。
  • 假设您使用的是 gcc,请参阅gcc.gnu.org/onlinedocs/gcc-10.2.0/gcc/Zero-Length.html
  • 你必须使用%zu来打印sizeof的结果

标签: arrays c declaration undefined-behavior sizeof


【解决方案1】:

这段代码sn-p

char vec[0];
vec[0] = 1;

调用未定义的行为。

你不能声明一个元素为零的数组。

来自 C 标准(6.7.6.2 数组声明符)

1 除了可选的类型限定符和关键字 static, [ 和 ] 可以分隔表达式或 *。如果他们分隔一个表达式 (指定数组的大小),表达式应具有 整数类型。 如果表达式是一个常量表达式,它应该 具有大于零的值。 元素类型不得为 不完整或函数类型。可选类型限定符和 关键字 static 只能出现在函数的声明中 具有数组类型的参数,然后仅在最外面的数组中 类型推导。

注意这些 printf 调用中使用了不正确的转换说明符

printf("\n SIZEOF: %li", sizeof(vec));
printf("\n VEC[0]: %li", vec[0]);

对于由运算符sizeof 返回的类型为size_t 的值,您应该使用转换说明符%zu,对于类型为char 的对象,您应该使用转换说明符%c

至于你的问题

为什么“vec[0]”的大小为“0 字节”,即使我添加了值“vec[0] = 1” ? (如果我不添加这个值,只需声明向量“char vec[0] 或 int vec[0]" 输出相同)。

那么编译器应该发出一个与数组的无效声明相关的消息。

至于输出,那么由于数组不是可变长度数组,因此表达式sizeof( vec ) 的值在编译时进行评估。编译器看到元素的数量等于0,并将表达式sizeof( vec ) 计算为0 * sizeof( char )。因此这个表达式总是产生0,与数组元素类型无关。

【讨论】:

  • 如果你想打印一个字符作为字符,你只能使用%c。如果要将 char 打印为(十进制)整数,请使用 %i%d
  • 在很多编译器中,声明一个包含 0 个元素的数组是合法的。当结构的最后一个字段是零长度数组时,它特别有用。
  • @abelenky 作为结构成员的灵活数组和问题中的此类声明是两件不同的事情。此外,灵活的数组成员被声明为具有不完整的类型。所以你的评论没有意义。
  • “你不能声明一个元素为零的数组。” - 是的,在某些情况下你可以。您的一揽子陈述充其量是误导性的,更有可能是错误的。
  • @VladfromMoscow:C 标准禁止“严格符合 C 程序”中的某些结构。另一方面,它允许“符合 C 程序”使用至少被一个“符合 C 实现”。根据标准的术语,存在将有用地处理大小为零的数组声明的 C 实现这一事实足以在“符合 C 程序”中允许这样的构造。
【解决方案2】:

vec 被定义为一个大小为零的数组。零元素的大小为零,这似乎是明智的。为vec[0] 赋值会覆盖某处的内存。

【讨论】:

    【解决方案3】:

    数组必须定义为正数。

    您创建了一个大小为 0 的文件,这是违反约束的,因此您的代码显示 undefined behavior

    【讨论】:

    • gcc 实际上允许 0 长度数组作为扩展(早于 C99 灵活数组成员,旨在解决相同的问题)。但是,像这样取消引用仍然是未定义的。见gcc.gnu.org/onlinedocs/gcc-10.2.0/gcc/Zero-Length.html
    • @Shawn:你仍然不应该在结构之外使用它们。
    • @Joshua 但是你可以。文档警告不要这样做,但它是允许的。
    • @Shawn:C 标签表示它是针对 ISO 9899 标准中定义的 C 的问题,除非另有说明。当 GCC 处于接受零长度数组而没有诊断消息的任何模式时,它没有实现 ISO 9899 标准中定义的 C,并且它的行为与 FORTRAN 编译器的行为没有更多的相关性,因为谁都没有实现标准中定义的 C。
    • 实际编译器的真实世界行为与我们这些不住在象牙塔里的人非常相关。我在 90 年代开始回想起 comp.lang.c。
    【解决方案4】:

    当您编写 vec[0] = 1; 时,实际上并没有在长度为 0 vec 的“数组”中填充位置。

    请记住,当您声明一个长度为 N 的数组时,它的有效索引是 0, 1, 2 ... N-1。如果数组的大小为0,那么有效的索引是什么?一个都没有!

    这与未定义的行为相同:

    int data[3] = { 1, 2, 3 };
    data[10000] = 10;
    

    写入vec[0] 可能在您的系统上工作,但它仍然不是属于vec 的内存。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-29
      • 2012-08-27
      • 2014-01-29
      • 2019-06-01
      • 2012-01-29
      相关资源
      最近更新 更多