C++ C 程序中带有默认参数的头文件
C++ header file with default arguments in C program
我有一个C++库,其中的函数在头文件中声明。我的函数声明包含默认参数。
我想通过 Wolfram Mathematica WSTP 模板编译器 (wscc) 在 Mathematica 中使用这个库。这需要为我的库编写一个 C 接口。我用过这个模式
#ifdef __cplusplus
extern "C" {
#endif
double my_function(double x, double abs_error = 1E-3);
#ifdef __cplusplus
}
#endif
防止我的库中的名称篡改(使用 C++ 编译)。但是默认参数呢?我不认为它们是标准的C。从 Wolfram Mathematica WSTP 模板编译器 (wscc),我发现
错误:在"="标记之前应使用";"、"、"或")" 双abs_error = 1E-3,
我是否必须进行单独的 C 和 C++ 声明(实际上是两个头文件)?这是一个常见问题还是与我使用 wscc 有关?也许 wscc 不支持这种语法,尽管它通常是可以接受的?
C 不支持默认参数。
因此,我假设您想为C++代码保留它们,但是您可以要求 C 调用者(在您的例子中为 Mathematica)为所有参数传递值。
一种可能的方法是定义一个宏,该宏在 C++ 中扩展到默认值初始值设定项,但在 C 中不扩展到任何值。它并不漂亮,但它有效:
#ifdef __cplusplus
#define DEFAULT_VALUE(x) = x
#else
#define DEFAULT_VALUE(x)
#endif
#ifdef __cplusplus
extern "C" {
#endif
void foo(int x DEFAULT_VALUE(42), void *y DEFAULT_VALUE(nullptr));
// In C, this becomes void foo(int x, void *y);
// In C++, this becomes void foo(int x = 42, void *y = nullptr);
#ifdef __cplusplus
}
#endif
与其使用宏黑客来解决 C 不支持默认参数的事实,不如引入一层间接
。首先是您的C++代码使用的C++特定标头(我任意将其命名为interface.h
.
double my_function_caller(double x, double abs_error = 1E-3);
和一个特定于 C 的标头(我任意将其命名为the_c_header.h
)
double my_function(double x, double abs_error);
/* all other functions that have a C interface here */
在实践中,人们可能希望在两个标头中包含守卫。
下一步是一个C++编译单元(我任意命名为interface.cpp
),它实际上与数学接口
#include "interface.h"
extern "C" // this is C++, so we don't need to test __cplusplus
{
#include "the_c_header.h"
}
double my_function_caller(double x, double error)
{
return my_function(x, error);
}
然后就是如何调用函数的问题。 如果调用方C++,那么它需要做的就是
#include "interface.h"
// and later in some code
double result = my_function_caller(x);
double another_result = my_function_caller(x, 1E-6);
如果调用者是 C(使用 C 编译器构建),它只需
#include "the_c_header.h"
/* and later */
result = my_function(x, 1E-3);
another result = my_function(x, 1E-6);
与基于宏观的解决方案相比,这显然有优点和缺点,包括:
没有宏- 的传统缺点(不尊重范围,没有与其他宏的意外交互,与一些C++开发指南相冲突,这些指南禁止将宏用于除包含保护之外的任何东西)。
- 明确区分哪些代码是 C,哪些代码是 C++:只有
interface.cpp
需要注意同时具有#include "the_c_header.h"
和#include "interface.h"
,并担心 C++ 与 C 的接口机制。 否则,C 编译单元(使用 C 编译器编译)只需要#include "the_c_header.h"
,C++编译单元只需要#include "interface.h"
。 interface.h
可以使用任何C++语言功能(不仅仅是默认参数)。 例如,如果您愿意,可以将其声明的所有函数放在名为mathematica
的命名空间中。 使用您的函数C++开发人员不需要关心该调用中实际上隐藏着一个 C 代码接口。- 如果你决定将来使用mathematica以外的其他东西重新实现
my_function()
,你可以。 只需放入the_c_header.h
和interface.cpp
的替代品,然后重建。 关注点的分离意味着没有必要更改interface.h
,所有C++调用者甚至不需要在增量构建中重新编译(当然,除非您出于其他原因更改interface.h
)。 - 实际上,构建过程将检测两个头文件的错误用法。 C 编译器会因使用特定于C++的功能而阻塞
interface.h
。 C++编译器将接受extern "C"
上下文之外的the_c_header.h
内容,但如果任何C++代码直接调用my_function()
,结果将是链接器错误(链接将需要名称损坏的定义)。
简而言之,这比宏观方法需要更多的努力来设置,但从长远来看更容易维护。
extern C 所做的不仅仅是停止名称重整。该函数具有 C 调用约定。它告诉CPP编译器"你现在应该说C"。这意味着异常不会传播,等等。AFAIK C 没有默认值。
您可以在 CPP 文件中实现一个具有 C 调用约定的函数,这有时非常有用。你可以让 C 调用 CPU 代码的位,这很有用。
我的怀疑是编译器如何处理默认值取决于编译器编写者。如果这是真的,我至少可以想到几种方法,其中一种不涉及在调用my_function
时将abs_error
的值放在堆栈上。例如,编译器可能会在堆栈上包含一个参数计数,函数本身使用该计数来发现尚未传递abs_error
并设置默认值。然而,如果这样的编译器使用具有 C 调用约定而不报告错误的函数这样做,那么它确实会非常不友好。我想我会测试它,只是为了确定。
- 在 cpp 文件中隐藏采用模板参数引用的方法
- 读取大文件(>2GB)(文本文件包含以太网数据)并通过不同参数随机访问数据的最佳方法是什么?
- 是否可以在命令行中将输入参数传递给可执行文件
- 如何使用输入参数作为文件的传递?
- 隐蔽的 gcc 参数到 CMake 文件
- 生成文件文件名参数
- 在实现文件中使用模板参数声明方法
- 提供变量作为 MATLAB 系统命令的输入参数,以便C++可执行文件
- 如何在 c++ 窗口中将参数和返回的退出值传递到批处理文件/从批处理文件获取返回的退出值
- 编写一个将 LLVM IR 文件作为命令行参数的程序
- 通过命令行参数获取llvm ir文件时面临问题
- 如何使输入文本文件成为构造函数参数?c++
- (C/C++)fscanf_s从txt文件以字符形式读取数组时缺少整数参数错误
- 如何在不使用文件扩展名的情况下使用命令行参数打开C++中的文本文件?
- 读取用户必须提供一些参数的文件
- 如何使用 QProcess 设置参数以运行类文件?
- 可变参数模板在目标文件中有重复的符号?
- c++ 文件的参数
- accept(..) 似乎正在修改我给它的文件描述符参数
- C++ 找不到命令行参数(文件)