【问题标题】:Variable Length Array with length 0?长度为 0 的可变长度数组?
【发布时间】:2014-07-27 18:24:09
【问题描述】:

在 C 中,通常不允许数组的大小为 0(除非我使用一个或其他编译器端扩展)。

OTOH,有些 VLA 的长度可能会变成 0。

他们允许吗?

我说的是下面的代码:

void send_stuff()
{
    char data[4 * !!flag1 + 2 * !!flag2];
    uint8_t cursor = 0;
    if (flag1) {
        // fill 4 bytes of data into &data[cursor]
        cursor += 4;
    }
    if (flag2) {
        // fill 2 bytes of data into &data[cursor]
        cursor += 2;
    }
}

结果是一个 data 数组,长度为 0、2、4 或 6,具体取决于标志的组合。

现在的问题是:对于数组长度为 0 的情况,此代码是否有效?

【问题讨论】:

  • @AntonH 它不适用,因为它是关于结构中的数组,而不是 variable-length 数组。
  • @AntonH 这与此无关。这个问题是关于编译器扩展的,它在 C99 之前是合理的。这个问题是关于可变长度数组的,它只在 C99 中可用。两者之间没有没有交集。
  • @glglgl 我的错,读得太快了。
  • @pascal-cuoq 我的错,读得太快了。
  • 顺便说一句:建议的解决方法:char data[1 + 4 * !!flag1 + 2 * !!flag2];。当然,这在以后调用sizeof data 时会遇到麻烦。

标签: c c99 language-lawyer variable-length-array


【解决方案1】:

这是无效的,如果我们转到draft C99 standard 部分6.7.5.2 数组声明符5段说(强调我的):

如果大小是一个不是整数常量的表达式 表达式:如果它出现在函数原型范围的声明中, 它被视为被 * 替换;否则,每次都是 评估它应该有一个大于零的值。[...]

事实上,clang 使用 -fsanitize=undefined 标志为未定义行为启用 sanitizer 可以为这种情况生成运行时警告 see it live

运行时错误:可变长度数组边界的计算结果为非正值 0

【讨论】:

  • 在 C11:6.7.6.2 §5 由于添加而移动。刚刚添加以供那些查看较新文档的人参考。
  • @Deduplicator 很有趣,但这个问题被专门标记为C99
  • 感谢您的回答。所以我得写uint8_t datalen = 4 * !!flag1 + 2 * !!flag2]; char data[datalen ? datalen : 1];之类的东西。我想以最初预期的方式声明数组会产生 UB,即使我不访问它? (在给定的情况下,cursor 为 0,例如,memcpy() 将复制大小为 0,因此实际上不会发生访问...
  • 0 长度数组(包括 VLA)是有效的扩展。但是,必须在首次使用时诊断 0 长度的常量大小数组,因为它们违反了编译时约束。
  • @glglgl:简单地无条件地分配数组一个大于必要的元素可能比仅在“必要”时尝试这样做更有效。更好的是编译器编写者公开声明任何不愚蠢的编译器都应该能够处理零大小的极端情况,无论标准是否强制要求它。
猜你喜欢
  • 2017-11-10
  • 2020-11-20
  • 1970-01-01
  • 1970-01-01
  • 2011-01-20
  • 2012-12-17
  • 2016-04-15
  • 1970-01-01
相关资源
最近更新 更多