C++未定义对已定义函数的引用

45

我无法弄清楚为什么这不起作用。 我会上传我的三个文件,希望有人能告诉我为什么它会抛出这个错误。 我正在使用g ++编译程序。

程序:

#include <iostream>
#include "h8.h"

using namespace std;

int main()
{
  char sentence[MAX_SENTENCE_LENGTH];
  char writeTo[] = "output.txt";
  int distanceTo,likePosition, length, numWords;
  cout << "ENTER A SENTENCE!   ";
  cin.getline(sentence, 299);
  length = strlen(sentence);
  numWords = wordCount(sentence, length);
  for(int x = 0; x < 3; ++x)
  {
    likePosition = likePos(numWords);
    distanceTo = lengthTo(sentence, likePosition, length);
    insertLike(sentence, distanceTo, length, writeTo);
  }
  return 0;  
}

函数文件:

void insertLike(const char sentence[],  const int lengthTo, const int length, char writeTo[])
{
  char part1[MAX_SENTENCE_LENGTH], part2[MAX_SENTENCE_LENGTH];
  char like[] = " like ";
  for(int y = 0; y < lengthTo; ++y)
    part1[y] = sentence[y];
  for(int z = lengthTo+1; z < length - lengthTo; ++z)
    part2[z] = sentence[z];
  strcat(part1, like);
  strcat(part1, part2);
  writeToFile(sentence, writeTo);
  return;
}

头文件:

void insertLike(const char sentence[], const int lengthTo, const int length, const char writeTo[]);

错误正是:

undefined reference to 'insertLike(char const*, int, int, char const*)'
collect2: ld returned 1 exit status
6个回答

31

insertLike的声明和定义具有不同的writeTo参数。

在你的头文件中,你有:

void insertLike(const char sentence[], const int lengthTo, 
                const int length, **const char writeTo[]**);

在你的函数文件中:
void insertLike(const char sentence[],  const int lengthTo, 
                const int length, **char writeTo[]**);

C++ 允许函数重载,即可以有多个具有相同名称的函数/方法,只要它们具有不同的参数。参数类型是函数签名的一部分。

在这种情况下,将 const char* 作为第四个参数的 insertLike 和将 char * 作为第四个参数的 insertLike不同的函数


33
有时候只需要多一双眼睛,伙计。 :) 我记得当我在学习C语言时,有时候我会花半天时间在键盘前挣扎和沮丧,然后我的岳父回家来,指着我的肩膀说:"你这里缺了一个分号。">.> - Mud
13
嗯,我从来没有岳父。可能这就是为什么我花了超过半天的时间在键盘上烦恼地敲打头部的原因 :-) - m-ric
2
有没有办法让机器帮我捕捉这个错误? - ulidtko
5
这句话的意思是:“机器确实捕捉到了错误,问题在于提问者不理解机器告诉他的信息。我认为编译器可以识别声明的函数和定义的函数之间的相似之处,并给出有帮助的建议(‘您是不是想要……?’)。” - Mud
我在尝试在 C 项目中编写 C++ 代码时(不同的配置),遇到了类似的错误信息。 - morteza

29
尽管之前的帖子已经涵盖了您遇到的错误,但是如果您没有告诉编译器使用C链接,当尝试使用g ++编译C代码时,可能会出现“未定义引用”的链接器错误。
例如,在您的C头文件中,您应该这样做:
extern "C" {

...

void myfunc(int param);

...

}

为了让'myfunc'在C++程序中可用。
如果您仍然希望从C中使用它,请将extern "C" {}包装在#ifdef __cplusplus预处理条件中,例如:
#ifdef __cplusplus
extern "C" {
#endif

这样,当使用C编译器时,extern块将会被“跳过”。

链接器确实应该检查这种情况并告诉您函数的未混合版本已定义! - jtbr
@karora,你的补充非常好,不过这个问题只标记了“c++”,所以我认为在C语言中使用相同代码的能力应该更多作为一个额外的备注。 - leftaroundabout
1
@leftaroundabout 或许这个问题也应该打上 C 标签,因为这种错误通常发生在两种语言之间的无人区。我的 C 代码一直运行得很好,直到我不得不从一个 C++ 程序中调用它,但当我按照这里推荐的更改后,它开始适用于 C++,但却破坏了我的工作中的 C 程序,因此我提出了这个建议。 - karora

26

您需要将所有源文件编译和链接在一起:

g++ main.c function_file.c

1
我也遇到了同样的问题,尝试在Debian机器上编译一些VS代码,结果找到了这个答案,非常感谢! 你甚至可以使用“g ++ * .c”进行编译,就像https://dev59.com/h3A75IYBdhLWcg3wm6ax#FZ2cEYcBWogLw_1byOeA中所述。 - ᴍᴇʜᴏᴠ
我可以按照上述方法(从.C文件编译)并成功完成,但是当我从.O目标文件编译(链接)时,它会失败,我必须额外修改一些声明才能使其正常工作。 - Yan King Yin

5
如果您正在使用CMake,也可能会发生这种情况。如果您创建了一个新类并想要实例化它,在构造函数调用时,即使头文件和cpp文件正确,如果您没有相应地修改CMakeLists.txt,则会收到此错误。
使用CMake时,每次创建新类之前,在使用头文件、cpp文件和任何其他可编译文件(如Qt ui文件)之前,必须将它们添加到CMakeLists.txt中,然后重新运行存储CMakeLists.txt的cmake .命令。
例如,在这个CMakeLists.txt文件中:
cmake_minimum_required(VERSION 2.8.11)

project(yourProject)

file(GLOB ImageFeatureDetector_SRC *.h *.cpp)

### Add your new files here ###
add_executable(yourProject YourNewClass.h YourNewClass.cpp otherNewFile.ui})

target_link_libraries(imagefeaturedetector ${SomeLibs})

如果您使用的是命令file(GLOB yourProject_SRC *.h *.cpp),那么您只需要重新运行cmake .而不需要修改CMakeLists.txt

make rebuild_cache 是强制重新配置的另一种方式。此外,这也是为什么不要使用文件名 GLOB 构建您的 CMakeLists 的原因。毕竟,它们被称为 CMakeLists - ulidtko

2

如果您要包含依赖于其他库的库,则包含顺序也很重要:

g++ -o MyApp MyMain.o -lMyLib1 -lMyLib2

在这种情况下,如果MyLib1依赖于MyLib2,那么就没有问题。但是,如果反过来,你将会得到未定义的引用错误。

0
正如Paul所说,这可能是链接器的问题,而不是编译器错误。如果您仔细阅读构建输出/日志(可能需要查看单独的IDE窗口以查看完整详细信息),则可以确定问题是来自编译器(需要在代码中修复)还是来自链接器(需要在make/cmake/project级别上进行修复以包含缺少的库)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接