【问题标题】:Using function written in c++ in c code在c代码中使用用c++编写的函数
【发布时间】:2015-04-07 17:45:25
【问题描述】:

我正在做一个项目,其中一些人已经用 C++ 编写了代码,我们必须在我们的 C 代码中使用它。所以我尝试了以下测试来编写一个演示相同的测试程序:

头文件为:

 #ifndef h_files_n
    #define h_files_n

    #include<iostream>

    #ifdef __cplusplus
        extern "C" {
    #endif

    void add_func(int, int);

    #ifdef __cplusplus
        }
    #endif

    #endif

cpp 文件是:

#include"h_files.h"

void add_func(int num, int nums)
{
    std :: cout << "The addition of numbers is : "<< num+nums << std endl;
}

c文件是:

#include<stdio.h>
#include"h_files.h"

int main()
{
    printf("We are calling the C function form C++ file.\n");

    add_func(10,15);

    return 0;
}

makefile 是:

CC = gcc
inc = -I include

vpath %.c src
vpath %.cpp src
vpath %.o obj

all : $(addprefix obj/,functions.o main.o) run

run : main.o functions.o
    $(CC) -o bin/$@ $^

obj/%.o : %.cpp
    $(CXX) -c $(inc) $^ -o $@ -libstdc++

obj/%.o : %.c
    $(CC) -c $(inc) $^ -o $@

.PHONY : clean

clean :
    -rm -f obj/* bin/*

我收到以下错误:

g++ -c -I include src/functions.cpp -o obj/functions.o
gcc -c -I include src/main.c -o obj/main.o
gcc -o bin/run obj/main.o obj/functions.o
obj/functions.o: In function `add_func':
functions.cpp:(.text+0x1e): undefined reference to `std::cout'
functions.cpp:(.text+0x23): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
functions.cpp:(.text+0x2d): undefined reference to `std::ostream::operator<<(int)'
functions.cpp:(.text+0x32): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
functions.cpp:(.text+0x3a): undefined reference to `std::ostream::operator<<(std::ostream& (*)(std::ostream&))'
obj/functions.o: In function `__static_initialization_and_destruction_0(int, int)':
functions.cpp:(.text+0x68): undefined reference to `std::ios_base::Init::Init()'
functions.cpp:(.text+0x77): undefined reference to `std::ios_base::Init::~Init()'
collect2: error: ld returned 1 exit status
make: *** [run] Error 1
  • 如果我使用 g++ 作为链接器,那么它工作正常。但是 gcc 链接器给了我 问题。
  • 我想到的问题是 g++ 修改的函数名和 gcc 不会破坏函数名称(符号)。
  • 如果可能的话,是否有任何编译器标志可以避免名称修改。
  • 避免使用 g++ 链接器的原因是它将链接视为 C++ 样式,但基本代码是 C 语言,因此可能会在调用代码时引入一些错误。

请有人提出解决方案。

【问题讨论】:

  • 你不能在 C 程序中使用cout
  • 我会尝试在链接阶段使用g++g++ -o bin/run obj/main.o obj/functions.o
  • @Barmar 这不完全正确,这里没有问题。
  • @KhouriGiordano 对,但不感兴趣。带有函数定义的源文件被编译为 c++ 源代码。
  • 您遇到过哪些实际错误(与g++ 链接时)?你怕什么?

标签: c++ c linux gcc


【解决方案1】:

$(CC) -o bin/$@ $^

使用

run : main.o functions.o
    $(CXX) -o bin/$@ $^

而是使用 g++ 链接器将所有内容链接在一起,并自动设置链接的 libstc++.a 库的默认值。

否则,您需要明确指定 -lstc++ 作为附加库。


另外,如果你正在为你的 c++ 代码设计一个纯 c-API,你应该有

 #include <iostream>

仅限functions.cpp 源文件中的语句。从functions.h 中删除 c++ 标准头文件。


请不要在 c++ 头文件中使用using namespace std;。它很容易引发所有意想不到的命名空间冲突(没有人知道namespace std 中使用的所有名称)。

无论如何它都不应该出现在纯 c-API 头文件中。


如果您想拥有一个混合 c/c++ API 头文件,请将 所有 的 c++ 特定语句放在 c++ 保护中:

 #ifdef __cplusplus
 #include<iostream>

 class xyz; // A c++ forward declaration
 #endif

【讨论】:

    【解决方案2】:

    您应该通过 g++ 链接程序或手动指定 libstdc++ 库。

    【讨论】:

    • 链接到 g++ 可能会引入一些错误,因为它以 C++ 方式链接代码,但调用代码在 C 中。
    • @AbhijatyaSingh:您认为这会导致什么样的错误?只要翻译单元之间的调用约定和损坏的符号名称匹配(如果不匹配,链接就会失败),每个单元是用什么语言编写的并不重要。
    • @AbhijatyaSingh 如果你是对的,那么就不可能链接同时使用 C 和 C++ 代码的程序。既然这显然是可能的,那你一定是错的。在像您这样的合理平台上,C++ 链接要么与 C 链接相同,要么是 C 链接的超集。
    • @AbhijatyaSingh 事实上gccg++ 都没有进行任何链接操作。他们都将他们的选项转换为真实链接器ld 的新选项列表,并在目标文件上调用它。
    • @fjardon:你忘记了collect2在链接阶段的重要性和作用。
    【解决方案3】:

    避免使用g++链接器的原因是它将链接视为C++风格,但基本代码是C,所以它可能会在调用代码时引入一些错误

    这根本不是真的。

    当您进入链接阶段时,C 和 C++ 之间的区别主要是学术性的:您是在 机器代码 中链接对象,而不是 C 或 C++程序。

    您需要注意的是调用约定混乱的名称,但是如果这会在您的程序中引入不兼容,那么您将在链接中了解它-时间。它不会引入无声的错误,除非出现非常非常错误的情况。

    所以,“它可能会在调用代码中引入一些错误”是错误,您可以像其他人一样继续链接g++。 :) 因为与您的 C++ 代码的唯一不同之处在于它引用了标准库和 C++ 运行时,您根本离不开。

    【讨论】:

      【解决方案4】:

      如果我使用 g++ 作为链接器,那么它工作正常。但是 gcc 链接器给了我这个问题。

      这就是为什么你应该使用g++

      我认为问题是 g++ 修改了函数名,而 gcc 不会修改函数名(符号)。

      在编译 C++ 代码时,会使用名称修饰。编译 C 代码时,不使用名称修饰。这与链接无关,链接不关心符号是否具有错误的名称。

      如果可能的话,是否有任何编译器标志可以避免名称修改。

      这个问题是基于错误的假设,即名称修改与链接有关。

      避免使用g++链接器的原因是它将链接视为C++风格,但基本代码是C,所以它可能会在调用代码时引入一些错误。

      链接器并不关心代码最初是用什么语言编写的。它只是链接编译后的代码。

      如果 C 代码的链接方式必须与 C++ 代码不同,否则可能存在一些错误,那么您尝试做的事情将是不可能的——将无法链接最终的可执行文件。但既然我们都知道 C 和 C++ 代码可以在像您这样的合理平台上安全地链接在一起,您一定会担心不存在的问题。

      【讨论】:

        【解决方案5】:

        您通常应该使用带有 C++ 编译器的 C++ 库(如 g++)链接您的 C 程序,并且您很可能需要链接标准 C++ 库。 (否则)要小心:

        • 需要一些重要的 C++ constructor(例如 std::cout)的静态或全局数据 - 从概念上讲,它们应该在输入 C main 函数之前运行。另请参阅 GCC function attributes,尤其是 constructorvisibility 属性。
        • C++ 函数抛出 C++ 代码无法捕获的异常。如果您的 C 程序调用的 C++ 函数抛出未捕获的异常,您可能会遇到麻烦......(可能是未定义的行为,或提前终止)。当在内存不足的进程中调用 new 时,可能会发生这种情况。
        • 返回非 POD 聚合的 C++ 函数(但在 C 端声明此类函数时会遇到麻烦;使用 C++ struct 的所有数据成员字段声明 C 结构并不总是足够或正确的, 因为 C++ 类型需要调用它的析构函数,并且因为它可能会添加一些vtable 指针等...)
        • name manglingcalling conventions。您可能应该将 C 代码可见的每个 C++ 函数声明为 extern "C"

        严格来说,C++ 旨在与 C 的一个子集互操作,但反之则不行。

        也许可以使用 C++ 编译器编译您的 C 代码(并修复所有不兼容问题) -e.g.与g++ -std=c++11 -Wall -Wextra -g ...- 可能会更容易。如果您的 C 代码库很小(少于 100K 源代码行),您甚至可以考虑将其移植到 C++,并逐渐习惯性地使用 C++。请注意C++11C11(或C99)是不同的 语言(它们恰好有一些有限部分 兼容性)。

        实际上,使用g++链接。在几乎所有情况下,这都不会添加错误。如果是这样,请使用 g++ 编译所有代码并将所有 C 源文件重命名为 C++ 文件(例如,您的 .c 文件后缀变为 .cc)并将整个内容重新编译为 C++(当然通过更正您的“C " 程序直到它使 C++ 编译器满意为止)。

        【讨论】:

        • 先生!!!!这就是为什么我要避免使用 g++ 链接器的原因,因为可能有一些 c++ 特定的代码在 C 中调用时可能会由于 C++ 的链接方式而导致错误。
        • 相反,你不应该避免链接到g++,但是你几乎必须链接到g++
        • @AbhijatyaSingh:先生!!!!!!您还没有解释为什么您认为这“可能导致错误”。我们不同意。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-21
        • 2012-07-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多