【问题标题】:Building an R package with Rcpp which contains C source and header with restrict qualifier?使用 Rcpp 构建包含 C 源代码和带有限制限定符的标头的 R 包?
【发布时间】:2014-11-29 04:25:01
【问题描述】:

我有一个第三方源文件和相应的头文件(包含 GSL 的声明和包含指令等),它们是用 C 编写的。我正在尝试围绕这些源文件构建一个 R 包,基本上是为函数制作一个包装器使用 Rcpp。问题是这些文件包含不属于 C++ 标准的限制限定符,因此 R CMD INSTALL 无法编译包。它确实对 .c 文件使用 C 编译器,但是 想用 C++ 编译器编译 .h 文件,但它失败了。 当它在头文件(包含在 .cpp 文件中)找到限制时失败。

我不太熟悉 C 和编译器以及 Rcpp 等,所以我不确定这里最好的方法是什么?

最简单的事情可能是删除限制关键字。这就是我目前所做的(当我从头文件中删除限制但将它们留给 .c 文件时,我很惊讶 R CMD INSTALL 工作)。但我宁愿不更改 .c 和 .h 文件,因为它们也被其他人用于非 R 环境(可执行文件和 Python 中),并且所有项目都有相同的文件会很好。

我还尝试定义空关键字restrict,以便如果编译是在C++ 编译器中完成的,它只会从函数定义中“删除”restrict,但我无法完成这项工作。我在某处读到过类似的方法,但显然它不起作用。

如果我能以某种方式告诉编译器(通过 Makevars 或其他方式?)特定的 .h 文件应该用 C 编译器编译,它会起作用吗?还是 C++ 函数调用这些函数会有问题?

或者,如果这些函数是通过 C++ 包装器从 R 调用的,那么整个关键字是否会影响性能?

一件事就是放弃 Rcpp 并使用 .C 而不是来自 R 的 .Call,但由于性能是这里的关键,这并不是一个好的选择,因为我知道 .Call 更快(更可靠)。

请注意,这个包最终会找到通往 CRAN 的途径,因此该解决方案应该是相当可移植的。似乎有一些 C++ 编译器特定的关键字用于限制,但我想这些不是一个选项,因为可移植性。

【问题讨论】:

  • 当您说将restrict 定义为空不起作用时,究竟发生了什么?另外,我很困惑:为什么 Rcpp 试图编译你的头文件?它不只需要编译你的 .c 文件吗?
  • 哦,是的,我写错了(我真的是这些东西的新手......),Rcpp 没有编译头文件,但无论如何都会用它做一些事情(因为我将它包含在 .cpp 文件中,所以我可以调用这些函数)。我收到的错误消息是“在 xR.cpp:3:0:xh:77:34 中包含的文件中:错误:在 'input' 之前需要 ',' 或 '...'”(我有变量 double const* 限制输入在函数声明中)。

标签: c++ c r rcpp restrict-qualifier


【解决方案1】:

听起来您正在制作一个执行#include <x.h> 的.cpp 文件,其中x.h 是使用restrict 的C 头文件。如果这是真的,我认为您可以修改您的 .cpp 文件来执行此操作:

#define restrict // nothing
extern "C"
{
#include <x.h>
}

然后编译您的 C++ 代码将看不到 restrict 关键字,而且我已将标头包装在 extern "C" 中,因为如果标头本身在内部没有这样做,您需要这样做,以便您的 C++编译器不会对内部声明的函数应用 C++“名称修饰”。

【讨论】:

  • 谢谢你,做到了。我尝试了 extern "C" 没有限制定义和其他方式,但忘记一起使用它们。我仍然想知道的是那个空定义会影响哪里。我的意思是 .c 文件中函数定义的限制是什么?
  • 啊哈,对。所以 restrict 在 C 中的意思是“这个指针不别名另一个”。由于您的 C++ 代码现在删除了 restrict 关键字,因此您(或者更确切地说,您的 Rcpp 包装函数)有责任确保您不会将相同或重叠的指针作为两个参数传递给 C 函数。例如,如果函数是“add”,则不能尝试执行add(&amp;x, &amp;x),而是将 x 复制到 y 中并执行add(&amp;x, &amp;y)。可能这对你来说没什么大不了的,但也许你需要在调用 C 之前检查你的值。
  • 是的,我明白了,但是为什么编译器没有给出声明和定义不同的错误?还是限制的新定义也会影响 .c 文件?
  • 编译器不知道。 restrict 关键字不会更改函数签名,因此您可以在声明中使用或不使用该关键字来调用它。但是如果你用两个别名指针调用函数,你将有未定义的行为(也许它会工作,也许它会崩溃,这取决于优化器对函数实现的疯狂程度)。由于 C 中没有函数名重载,您甚至可以更改声明中的参数数量,程序仍然可以编译,但它可能会崩溃等。C++ 不同,因为重命名的名称包括 const 等。
猜你喜欢
  • 2017-03-23
  • 1970-01-01
  • 1970-01-01
  • 2012-01-18
  • 1970-01-01
  • 2021-04-24
  • 1970-01-01
  • 2017-05-24
  • 1970-01-01
相关资源
最近更新 更多