【问题标题】:Using VLAs in a C++11 environment在 C++11 环境中使用 VLA
【发布时间】:2016-10-31 07:49:12
【问题描述】:

我得到了已经存在的 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]);
                                 ^~~~~~

我想我在某处读到 VLA 在 C11 中成为可选的。这是否意味着 gcc 完全摆脱了它?如果是这样,除了extern "C",我还能做什么?当然,我可以使用较旧的 C 标准编译源代码。但我必须以某种方式包含标题。有什么想法吗?

重写整个事情只是万不得已的方法。

【问题讨论】:

  • 除了使用 C 编译器编译源代码之外,您别无选择,因为 C++ 没有可变长度数组。无论如何,我认为可变长度数组作为指向第一个元素的指针传递。因此,如果您在 C++ 代码中将最后一个函数声明为 extern "C" { void foo(int n, double * l, double * x, double * b); },则应该正确调用它。 (不过,这只是一个猜测。)
  • 您可能希望使用启用 C++14 功能的--std=gnu++14,而不是启用 C++14 功能并禁用所有 g++ 扩展的--std==c++14
  • VLA 在标准 C++ 中无效,在 C11 中的 C 中是可选的。无论 C 是否支持它们,最好避免尝试在 C++ 中使用它们。您将需要编写一个 extern "C" 包装函数,该函数提供 C++ 可接受的接口,并将其参数传递(或复制)到使用 VLA 的函数。该包装器需要作为 C 来实现(并因此被编译),但它必须提供一个有效的 C++ 签名(返回类型和参数类型)。就我个人而言,我会将函数重写为 C++,然后就可以完成了。
  • gcc 在 C11 模式下继续支持 C 代码中的 VLA (-std=c11);它没有定义宏__STDC_NO_VLA__。 (这与 C++ 代码无关。)
  • VLA 从来都不是 C++ 的一部分,extern "C" 并不会神奇地使它们如此,无论版本如何(这里只是说明显而易见的)。

标签: c++ c++11 c99 c11 variable-length-array


【解决方案1】:

我想在我的 C++11 项目中包含标题。由于 C++ 不允许这种结构,我使用 extern "C" 来包含这些头文件。但是编译器根本不喜欢这样。

确实,这是一个问题,因为 C++11 没有 VLA。您可能需要考虑用 C 编写一个包装器,将其编译为 C 并在 C++ 中使用它。


我想我在某处读到 VLA 在 C11 中成为可选的。这是否意味着 gcc 完全摆脱了它?

不,当将代码编译为 C11 时,gcc 仍然支持 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 的严格超集

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-29
    • 2016-07-11
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    • 2021-11-12
    • 1970-01-01
    相关资源
    最近更新 更多