从(C)头文件调用C++函数会导致链接器错误

我正在集成一个库 (lwip),我想将日志记录机制重新路由printf到我自己编写的内容(直接记录到我的 uart)。

在某些头文件中存在以下代码

/** Platform specific diagnostic output.n
 * Note the default implementation pulls in printf, which may
 * in turn pull in a lot of standard libary code. In resource-constrained 
 * systems, this should be defined to something less resource-consuming.
 */
#ifndef LWIP_PLATFORM_DIAG
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#include <stdio.h>
#include <stdlib.h>
#endif

我替换了这条线

#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)

#define LWIP_PLATFORM_DIAG(x) do {logLineToUart x;} while(0)

我对我的函数使用与签名相同的printf签名:

void logLineToUart(const char * log, ...);

我将该函数放在我自己的标头中lwiplogging.h,我将其包含在定义的标头中LWIP_PLATFORM_DIAG

而且,我在 C++ 文件中实现了该函数:

void logLineToUart(const char * log, ...)
{
    uart3.Write(log);
    uart3.Write("rn");
}

注意:uart3 是我Uart班级的一个对象。因此它是 C++ 代码。我怀疑这是问题所在,但我不知道如何纠正我的错误。添加extern "C"到函数似乎也不能解决它。

我得到的链接器错误:

Linking .piobuildnucleo_f446zefirmware.elf
.pio/build/nucleo_f446ze/lib997/lwip/api/api_lib.o: In function `netconn_send':
api_lib.c:(.text.netconn_send+0x26): undefined reference to `logLineToUart'
.pio/build/nucleo_f446ze/lib997/lwip/api/sockets.o: In function `tryget_socket_unconn_nouse':
sockets.c:(.text.tryget_socket_unconn_nouse+0xa): undefined reference to `logLineToUart'
.pio/build/nucleo_f446ze/lib997/lwip/api/sockets.o: In function `get_socket':
sockets.c:(.text.get_socket+0x14): undefined reference to `logLineToUart'
.pio/build/nucleo_f446ze/lib997/lwip/api/sockets.o: In function `lwip_connect':
sockets.c:(.text.lwip_connect+0x22): undefined reference to `logLineToUart'
sockets.c:(.text.lwip_connect+0x38): undefined reference to `logLineToUart'
.pio/build/nucleo_f446ze/lib997/lwip/api/sockets.o:sockets.c:(.text.lwip_connect+0x7e): more undefined references to `logLineToUart' follow
collect2.exe: error: ld returned 1 exit status
*** [.piobuildnucleo_f446zefirmware.elf] Error 1

我究竟做错了什么?

更新

将函数声明为 extern "C" 时出现的错误

更新 2:

这确实编译:

#ifdef __cplusplus
extern "C" {
void logLineToUart(const char * log, ...);

#endif

void logLineToUart(const char * log, ...);

#ifdef __cplusplus
}
#endif

回答

extern "C" void logLineToUart(const char * log, ...);

您需要告诉它在第一次看到名称 C-linker 时使其兼容。

更新

extern "C"如C ++编译时,只有。它不是 C 中的合法语法。您可以单独使用extern(如果您不使用它,则暗示了它)。

社论

这不是很友好...... C++ 通过接受不适用于 C++ 的语法来适应与 C 共享头文件,只是为了便于使用相同的头文件内容。特别是,(void)用于空参数列表(这是“令人厌恶的”)并允许在可变参数函数参数列表中使用逗号(这(int x ...)是 C++ 最初定义它的方式;当相同的功能被合并到 ANSI C 中时,它们使用(int x, ...)了一个多余的逗号,即语法不需要。)C++ 编译器接受这两者,以便更容易地使用 C 头文件......

但是,您必须添加extern "C"所有内容。无论如何,这引入了条件编译,即使 C++ 接受 C 语法。请注意,对于单个声明,如果省略它,extern int foo (int);extern是允许和隐含的。如果 C 编译器允许链接规范,即使只有“C”可用,它也会使生活更轻松。请注意,在大多数情况下,C 和 C++ 实现是相同的编译器套件,并且通常一种语言支持另一种语言的某些功能作为扩展。如果在 C 模式下gcc支持 etc.会很酷extern "C++",因为该代码库当然知道名称如何对参数进行编码。


以上是从(C)头文件调用C++函数会导致链接器错误的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>