【问题标题】:Using C Libraries for C++ Programs将 C 库用于 C++ 程序
【发布时间】:2012-08-17 11:20:31
【问题描述】:

我正在尝试使用使用 Qt 制作的 GUI 来控制 Dynamixel 伺服系统。 Dynamixel 提供了一组C libraries 来控制电机,而我所知道的制作 GUI 的唯一方法是 Qt,它本质上是 C++。是否可以以任何方式从 Qt C++ 代码中使用 Dynamixel C 库?

【问题讨论】:

    标签: c++ c robotics


    【解决方案1】:

    是的 - C++ 可以使用 C 库。

    这是一个使用 libc 主 C 库的示例

    #include <cstdio>
    
    int main()
    {
       printf("%s\n", "Hello world");
       return 0;
    }
    

    【讨论】:

    • 当然你使用的是cstdio的C++版本。要使用 C 语言,您需要 #include &lt;stdio.h&gt;
    • 头文件与链接的库无关——这个例子是为了证明C++代码可以使用C库函数编译
    • 是的,头文件不是库。标头将只有函数的原型,因此链接器将能够在 C 运行时库(libc,BTW)中找到。
    • 如果你想学究气 - 我也会;)。如果你在使用&lt;cstdio&gt; 时使用printf 而不是std::printf,那么你会得到未定义的行为 (17.6.1.2) “不确定这些名称是否首先在全局命名空间范围内声明,然后注入命名空间std 通过显式使用声明”。如果您使用的是std::printf,那么您只是间接使用了 C std 库,并且可能会通过 libstdc++
    【解决方案2】:

    当然... 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 开关位于您正在编译的代码或目标文件之后,如果您是库,则类似于 libjpglibrobotics等,当您将其附加到 -l 开关时,删除名称的 lib 部分。

    【讨论】:

    • 你为什么认为标题不这样做?
    • 我没有假设...我说“如果头文件还没有声明它们”
    • 名称和操作系统或它们没有出现的示例?
    • 所有主要库都已正确包装 AFAIK。来自第三方供应商(例如机器人制造商)的自定义库可能没有。这取决于。我见过一些旧的商业代码不是这样包装的。
    • 非常感谢库开关/标志出现在“我的”对象之后的提示。
    【解决方案3】:

    是的,C++ 可以使用 C++ 编译器编译 C,并且您可以将 C++ 与 C 链接。只要确保您调用的任何 C 函数都使用 C 链接。这是通过用 extern "C" 封装 C 函数的原型来实现的

    #ifdef __cplusplus
    extern "C"{
    #endif 
    
    void c_function_prototype();
    
    #ifdef __cplusplus
    }
    #endif
    

    您尝试使用的库的标头可能已经这样做了。

    【讨论】:

    • C 函数是指使用 C 编译器编译的函数,因此它的签名不会像 C++ 编译函数那样被破坏。那么在这种情况下,正如你所说,我们需要使用extern "C"来防止C++在调用它时破坏函数签名,这样才能在C库中正确找到该符号。
    • @LokiAstari 没问题,您有助于澄清我的回答。
    • 您可以使用 C++ 编译器编译大多数 C 声明,方法是指定 C 链接,但一般 C 代码并非如此,除非经过精心设计否则你会非常幸运。如果您尝试,您可能会遇到编译错误,但如果您不那么幸运,那么您可能会成功编译损坏的程序。
    【解决方案4】:

    不要忘记库标题周围的extern "C"。 在这里阅读。 How does C's "extern" work?

    【讨论】:

    • 你为什么认为标题不这样做?
    • 其实我的意思是“不存在就不要忘记”。
    【解决方案5】:

    您可以使用 C++ 中的 C 库...但是有一些注意事项。

    在 C++ 中使用第三方 C 库时需要注意的一件大事是错误处理。

    一些 C 库使用 setjmp/longjmp 等工具进行错误处理。 (lua 是一个显着的例子)。这意味着错误堆栈展开不会以正常方式发生,并且您可能会泄漏资源。诸如用于资源保护的通常 C++ RAII 风格的防护措施都失败了。 (对于 C++ 代码,这些调用比 goto 更糟糕)。

    异常也可能是一个问题。如果 C++ 异常传播到 C/C++ 边界,则应用程序可能会终止而不是传播异常。 (取决于 C 库的编译方式和您的操作系统等)(如果您将 C++ 函数作为回调传递给 C 库,您可能会遇到这种情况。)

    【讨论】:

      【解决方案6】:

      Rock Framework 中有一个用于 Dynamixel 舵机的 C++ driver

      【讨论】:

        【解决方案7】:

        是的。要使用 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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-09-08
          • 1970-01-01
          • 2011-04-15
          • 1970-01-01
          • 1970-01-01
          • 2012-02-15
          • 1970-01-01
          相关资源
          最近更新 更多