C 长度为0的可变长度数组?
在C语言中,通常不允许数组的大小为0(除非我使用一个或另一个编译器端扩展) OTOH,有些VLA的长度可能是0 允许吗 我说的是以下代码:C 长度为0的可变长度数组?,c,c99,language-lawyer,variable-length-array,C,C99,Language Lawyer,Variable Length Array,在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;
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;
}
}
结果是一个长度为0、2、4或6的数据
数组,具体取决于标志的组合
现在的问题是:对于数组长度为0的情况,这是有效的代码吗?如果我们转到
6.7.5.2
数组声明器第5段说(重点):
如果大小是非整数常量的表达式
表达式:如果它出现在函数原型范围的声明中,
将其视为替换为*;否则,每次都是
评估其值应大于零[…]
事实上,使用clang
为未定义的行为启用-fsanize=undefined
标志可以为这种情况生成运行时警告:
运行时错误:可变长度数组绑定的计算结果为非正值0
@AntonH它不适用,因为它是关于结构中的数组,而不是可变长度数组。@AntonH这与此无关。这个问题是关于一个编译器扩展的,它在C99之前是合理的。这个问题是关于可变长度数组的,它只在C99中可用。两者之间没有交叉点。@glglglgl我的错误,读得太快。@pascal cuoq我的错误,读得太快。顺便说一句:建议解决方法:
char data[1+4*!!flag1+2*!!flag2]代码>。当然,这在以后调用sizeof data
时会遇到问题。在C11:6.7.6.2§5中,它由于添加而移动。刚刚添加的内容供查看较新文档的人参考。@重复数据消除或有趣,但问题被特别标记为C99
。感谢您的回答。因此,我必须输入类似于uint8\u t datalen=4*!!flag1+2*!![2];字符数据[datalen?datalen:1]代码>。我想,即使我不访问它,以最初预期的方式声明数组也会产生UB?(因为在给定的情况下,游标
为0,例如,memcpy()
将获得要复制的大小0,因此有效地不会发生访问…0长度数组(包括VLA)是有效的扩展名。但必须在首次使用时诊断0长度的常量大小数组,因为它们违反了编译时约束。@GLGL:只需无条件地将数组分配给大于必需的一个元素,可能比仅在“必需”时才尝试分配数组更有效。更好的是,编译器编写者公开声明,任何不愚蠢的编译器都应该能够处理零大小角的情况,而不管标准是否强制要求它。