使用C ++标头在简单C程序中链接错误

时间:2011-07-27 03:33:16

标签: c++ c linker

我正在关注介绍教程http://www.linuxinsight.com/files/alp/alp-ch01-getting-started.pdf

我创建了源文件main.c,reciprocal.cpp和reciprocal.hpp。我已经能够成功编译这些文件。当我去链接它们时出现问题,我收到以下错误消息:

main.o: In function `main':
main.c:(.text+0x30): undefined reference to `reciprocal'
collect2: ld returned 1 exit status

我认为这在某种程度上没有正确使用头文件,但我真的不知道该尝试什么,因为我已经非常彻底地遵循了这些步骤。

如果有人知道为什么抛出这个错误我会非常感激。

由于

**更新 以下是三个源文件的代码:

的main.c

#include <stdio.h>
#include "reciprocal.hpp"

int main (int argc, char **argv) {
    int i;
    i = atoi(argv[1]);
    printf("The reciprocal of %d is %g\n", i, reciprocal(i));

    return 0;
}

reciprocal.cpp

#include <cassert>
#include "reciprocal.hpp"

double reciprocal(int i) {
    assert(i != 0);
    return 1.0/i;
}

reciprocal.hpp

#ifdef __cplusplus
extern "C" {
#endif

double reciprocal(int i);

#ifdef __cplusplus
}
#endif

我实际上已经修改了自最初发布以来的reciprocal.hpp。我做的唯一更改是从函数签名中删除extern关键字。它以前读过

extern double reciprocal(int i);

此更改允许我链接程序,现在我可以运行它。我认为可能发生的事情是,第二个外部正在压倒第一个外部。如果有人对此有任何见解,我会有兴趣知道。

感谢大家的帮助。

3 个答案:

答案 0 :(得分:5)

当您将C和C ++代码混合在一起时,您可能会遇到麻烦,因为这两种语言具有不同的链接。也就是说,如果您要打开已编译的C和C ++文件的目标文件,您会发现这些目标文件中的名称不同。

特别是,C ++编译器倾向于使用一种称为“名称修改”的技术,其中函数名称与关于其参数类型的额外信息混合在一起。例如,一个函数

char foo(int);

实际上可能有内部名称

char@foo@int

生成的目标文件内部。问题是C代码没有这样做,所以如果你编译了一个C文件并试图引用名称foo,链接器将找不到它,因为生成的函数名称C ++文件是char@foo@int而不是foo

要解决此问题,C ++有一个功能,允许您明确告诉链接器不要破坏名称并使生成的代码看起来像是用于C程序。为此,您可以声明C ++函数:

extern "C" char foo(int);

现在,生成的目标文件将包含名称foo,而不会以与C代码所期望的方式兼容的方式装饰。

要解决您的问题,请尝试将其中一个extern "C"声明添加到定义reciprocal的C ++源文件中。

注意:如果你有一个混合了C和C ++代码的项目,那么总是main函数编译为C ++代码。 C ++将额外的初始化和清理代码引入到C代码中不存在的可执行文件中。如果将main编译为C代码,则可能无法将此额外逻辑添加到程序中,因此您可能会在运行时遇到无法解释的崩溃。

希望这有帮助!

答案 1 :(得分:1)

将C ++文件链接到C文件最多也很困难。 C ++“破坏”了名称,以便可以发生重载。

您可以通过包含这样的倒数定义来防止错位:

extern "C" {
   reciprocal definition...
}

但如果你这样做,你也可以用C语言写一下......

你能制作一个main.cpp文件吗?

答案 2 :(得分:1)

您的reciprocal.hpp内容看起来无效,可能是#ifdef行中的拼写错误,__cplusplus拼写正确(应该有两个下划线)?