在C++11环境中使用可变长度数组(VLAs)

3

我有一段已经存在的 C 代码,它使用了 C99 风格的可变长数组(VLA),就像这样:

 int foo(int n, double l[n][n], double a[n][n]);

我想在我的C++11项目中包含头文件。由于C++不允许这种构造,因此我使用extern "C"来包含这些头文件。 然而编译器完全不喜欢这个。

./header.h:23:42: error: use of parameter outside function body before ‘]’ token
 void foo(int n, double l[n][n], double x[n], double b[n]);
                           ^
./header.h:23:45: error: use of parameter outside function body before ‘]’ token
 void foo(int n, double l[n][n], double x[n], double b[n]);
                              ^
./header.h:23:46: error: expected ‘)’ before ‘,’ token
 void foo(int n, double l[n][n], double x[n], double b[n]);
                               ^
./header.h:23:48: error: expected unqualified-id before ‘double’
 void foo(int n, double l[n][n], double x[n], double b[n]);
                                 ^~~~~~

我记得在C11中,可变长数组(VLAs)变成了可选项。这是否意味着gcc完全摆脱了它?如果是,除了使用extern "C"之外,我还能做什么?当然,我可以用较旧的C标准编译源代码。但我必须以某种方式包含头文件。有什么想法吗?

重新编写整个内容只会是最后的手段。


你没有其他选择,只能使用C编译器编译源代码,因为C++没有可变长度数组。我认为可变长度数组会被传递为指向第一个元素的指针。因此,如果你在C++代码中将最后一个函数声明为extern "C" { void foo(int n, double * l, double * x, double * b); },它应该可以正确调用。(不过这只是猜测。) - JohnB
你可能想要使用 --std=gnu++14,它启用了 C++14 的特性,而不是 --std==c++14,它启用了 C++14 的特性并禁用了所有 g++ 扩展 - Ben Voigt
VLAs在标准C++中无效,在C11中是可选的。无论它们是否被C支持,最好避免尝试在C++中使用它们。您需要编写一个extern "C"包装函数,该函数提供适用于C++的接口,并将其参数传递(或复制)到使用VLAs的函数中。该包装器将需要作为C实现(因此编译),但它必须提供一个有效的C++签名(返回类型和参数类型)。就个人而言,我会将该函数重写为C++并完成它。 - Peter
gcc在C11模式(-std=c11)中继续支持C代码中的可变长度数组(VLAs);它不定义宏__STDC_NO_VLA__。(这并不适用于C++代码。) - Keith Thompson
可变长度数组(VLAs)从未是C++的一部分,而extern "C"也不能使它们成为C++的一部分,无论版本如何(这里只是明显的陈述)。 - n. m.
所以我想这里的问题实际上是:VLAs是否是gnu++14的一部分?如果是这样,那听起来像是最好的解决方法。一个不太美观的解决方法是将源代码的一部分编译为C++,另一部分编译为C,然后编写包装函数来处理所有C++不支持的C特性。 - Lundin
1个回答

3
我想在我的C++ 11项目中包含头文件。由于C ++不允许这些类型的构造,因此我使用extern "C"来包含这些头文件。然而,编译器并不喜欢这个。
实际上,这是一个问题,因为C++11没有可变长度数组(VLA)。您可能需要考虑在C中编写包装器,在C中编译它,并在C++中使用它。
我记得在某个地方读到VLAs在C11中成为可选项。这是否意味着gcc完全摆脱了它?
不,gcc仍支持在C11编译代码时编译VLA。但是,这与您的问题无关,您的问题是关于C++11的,这是一种完全不同的语言,不支持VLA。
除了extern "C"之外,还有什么可以做吗?
单独使用extern "C"是无法帮助您的,因为正如我所解释的,C++11没有可变长度数组(VLA)。请注意,在C语言中,数组是连续序列,这意味着它是全部分配并且所有元素一个接一个发生的,因此这样的二维数组被表示为一个 n * n 元素的一维数组。您的包装器还应使用extern "C",将指向该压平数组第一个元素的double *转换为指向该压平数组的前n个元素的double (*) [n]。
这是在C11中进行的类型转换,不需要暴露给C++,因为采用指向 double * 的函数的函数编译为C11代码(而不是C ++ 11),并使用链接器链接到C ++ 11项目中。C ++ 11不需要看到函数下面的C11代码。
因此,您需要重新编写头文件(您可以独立于.h文件维护它作为.hpp文件),但这不是一个完全重写。至少希望您已经了解到,C ++不是C的严格超集。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接