【发布时间】:2012-08-17 11:20:31
【问题描述】:
我正在尝试使用使用 Qt 制作的 GUI 来控制 Dynamixel 伺服系统。 Dynamixel 提供了一组C libraries 来控制电机,而我所知道的制作 GUI 的唯一方法是 Qt,它本质上是 C++。是否可以以任何方式从 Qt C++ 代码中使用 Dynamixel C 库?
【问题讨论】:
我正在尝试使用使用 Qt 制作的 GUI 来控制 Dynamixel 伺服系统。 Dynamixel 提供了一组C libraries 来控制电机,而我所知道的制作 GUI 的唯一方法是 Qt,它本质上是 C++。是否可以以任何方式从 Qt C++ 代码中使用 Dynamixel C 库?
【问题讨论】:
是的 - C++ 可以使用 C 库。
这是一个使用 libc 主 C 库的示例
#include <cstdio>
int main()
{
printf("%s\n", "Hello world");
return 0;
}
【讨论】:
cstdio的C++版本。要使用 C 语言,您需要 #include <stdio.h>。
<cstdio> 时使用printf 而不是std::printf,那么你会得到未定义的行为 (17.6.1.2) “不确定这些名称是否首先在全局命名空间范围内声明,然后注入命名空间std 通过显式使用声明”。如果您使用的是std::printf,那么您只是间接使用了 C std 库,并且可能会通过 libstdc++。
当然... C 代码一直是从 C++ 调用的。例如,大多数操作系统库都是用 C 而不是 C++ 编写的。因此,每当您从 C++ 代码进行系统调用以执行移交给操作系统内核的任务时,这些都是通过 C 代码调用。
请确保在编译时包含正确的标头和针对相关 C 库的链接。如果头文件还没有声明它们,还记得使用extern "C" 为 C 库函数指定 C 链接。请记住,某些库可能没有专门使用extern "C" 声明它们的函数,但可能使用了预处理器令牌来这样做。因此,在假设库编写者尚未将其库定义为具有 C 链接之前,您还需要检查一下。
使用gcc 链接自定义库可以使用-l 开关完成。如果您需要为库所在的位置指定自定义目录,可以使用-L 开关完成。比如:
g++ -std=c++11 my_code.cpp -lmy_library -L/custom_directory_path
请注意,-l 和 -L 开关位于您正在编译的代码或目标文件之后,如果您是库,则类似于 libjpg 或 librobotics等,当您将其附加到 -l 开关时,删除名称的 lib 部分。
【讨论】:
是的,C++ 可以使用 C++ 编译器编译 C,并且您可以将 C++ 与 C 链接。只要确保您调用的任何 C 函数都使用 C 链接。这是通过用 extern "C" 封装 C 函数的原型来实现的
#ifdef __cplusplus
extern "C"{
#endif
void c_function_prototype();
#ifdef __cplusplus
}
#endif
您尝试使用的库的标头可能已经这样做了。
【讨论】:
extern "C"来防止C++在调用它时破坏函数签名,这样才能在C库中正确找到该符号。
不要忘记库标题周围的extern "C"。
在这里阅读。 How does C's "extern" work?
【讨论】:
您可以使用 C++ 中的 C 库...但是有一些注意事项。
在 C++ 中使用第三方 C 库时需要注意的一件大事是错误处理。
一些 C 库使用 setjmp/longjmp 等工具进行错误处理。 (lua 是一个显着的例子)。这意味着错误堆栈展开不会以正常方式发生,并且您可能会泄漏资源。诸如用于资源保护的通常 C++ RAII 风格的防护措施都失败了。 (对于 C++ 代码,这些调用比 goto 更糟糕)。
异常也可能是一个问题。如果 C++ 异常传播到 C/C++ 边界,则应用程序可能会终止而不是传播异常。 (取决于 C 库的编译方式和您的操作系统等)(如果您将 C++ 函数作为回调传递给 C 库,您可能会遇到这种情况。)
【讨论】:
Rock Framework 中有一个用于 Dynamixel 舵机的 C++ driver。
【讨论】:
是的。要使用 C 库函数,请在 .cpp 程序中使用如下所示的 extern "C" , myprog.cpp
extern "C" {
// C Function call
cfunc();
}
int main()
{
cfunc();
return 0;
}
这个cfunc应该在c库中定义如下 prog.c
#include <stdio.h>
void cfunc()
{
printf("This is from c library");
}
然后您需要为您的 C 库创建.o 目标文件和.so 共享目标文件,如下所示
$] gcc -c prog.c -o prog
$] gcc -shared -o libprog.so prog.o
$] export LD_LIBRARY_PATH=/path/to/clibrary:$LD_LIBRARY_PATH
$] g++ -L/path/to/clibrary myprog.cpp -o myprog.o -lprog
【讨论】: