为什么 clang 抱怨使用带有“-std=c99”标志的可变长度数组?

Why does clang complain about using variable-length arrays with '-std=c99' flag?

当我编译这个实验代码时:

int main(void)
{
    int foo = 5;
    char bar[foo];
}

with clang 和 '-Weverything' 或单独的 '-Wvla' 标志与 '-std=c99' 标志相结合, 我仍然收到警告:

warning: variable length array used [-Wvla]

Example here

尽管与后来的 C 标准(C11、C18 等)相比,符合 C99 的实现应该——其中 VLA 支持是可选的,无一例外地支持可变长度数组。


您是正确的,符合 C99 的实现 必须 支持 VLA,而实现可以符合后来的 C 标准而不支持 VLA。但我认为你只见树木不见森林:我认为上述标准之间的差异正是警告的重点。这并不是说您正在构建的代码可能会出错。相反,它警告您依赖的功能不是普遍向前兼容的,因此如果您尝试在其他地方构建代码,它可能会崩溃。

如果 Clang 认为 VLA 是 C99 的非标准扩展,那么它根本不应该在 -std=c99 模式下接受您使用 VLA 的代码。

人们可能希望避免在程序中使用可变长度数组的原因有很多,即使您使用的语言版本保证支持它们也是如此。其一,正如 John Bollinger 所提到的,以防万一您想与不支持它们的其他标准保持兼容性。

另一个是,在典型的基于堆栈的实现中,它们消耗的堆栈量在编译时可能是未知的,或者不受信任的用户可能会影响,并且此类实现通常没有检测堆栈溢出或从堆栈溢出中恢复的好方法。例如,Linux 内核开发人员出于这个原因决定不应在内核中使用 VLA,并且 using -Wvla 帮助他们执行此操作。

这些问题肯定不会适用于每个程序,这就是为什么 -Wvla 选项是 选项 的原因;无论出于何种原因,如果您想了解 VLA 在您的程序中的使用情况,您可以将其打开,如果您不这样做,则可以将其关闭。您选择使用 -Weverything 来打开所有存在的警告。这个标志并不是真正打算对程序员有用,因为正如您所注意到的,它会打开许多​​警告,这些警告仅在某些情况下对知道他们需要它们的人有用。它的意思是帮助调试编译器本身。

实际上,您已经告诉编译器 "issue all the warnings you can, even if they're not relevant in my situation",现在您问的是为什么收到与您的情况无关的警告:-)

符合 C99 的实现必须支持 VLA,但是使用 -Weverything 启用所有警告意味着 请编译器告诉我任何可能造成问题的事情。在潜在的问题中有许多一致的结构:

  • VLA 可能会给不完全符合规范的实现带来可移植性问题,其中有很多。使用 -Wno-vla 禁用此警告。
  • 某些运算符组合可能是由于程序员错误或对有时违反直觉的相对优先级的混淆造成的。该表达式仍然符合C标准,但编译器会发出警告,程序员可以添加括号以防止警告。
  • 测试表达式中的赋值是一致的表达式,但编译器会发出警告,因为它们可能是简单的拼写错误,其中 == 被拼错为 =
  • 未使用的变量不是错误,但会在 -Weverything
  • 下产生警告

不胜枚举。如果您要求更多警告,这在大多数情况下可以挽救生命,您可能需要优化 CFLAGS 以禁用某些选定的警告,例如 -Wno-vla 以编译您的程序,如果您确实有意使用 VLA。