简体   繁体   English

从 (C) header 文件调用 C++ function 给出 Z3175B426046787EECE737B7378 错误

[英]Call C++ function from (C) header file gives linker error

I am integrating a library (lwip) and I want to reroute the logging mechanism from printf to something I wrote myself (which logs directly to my uart).我正在集成一个库(lwip),我想将日志记录机制从printf重新路由到我自己编写的东西(直接记录到我的 uart)。

In some header file the following code exists在某些 header 文件中存在以下代码

/** 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

I replaced this line我换了这条线

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

with

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

I am using the same signature for my function as the printf signature:我为我的 function 使用与printf签名相同的签名:

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

And I placed that function in my own header lwiplogging.h , which I include in the header which defines LWIP_PLATFORM_DIAG我将 function 放在我自己的 header lwiplogging.h中,我将其包含在定义 LWIP_PLATFORM 的LWIP_PLATFORM_DIAG

And, I implement the function in a C++ file:而且,我在 C++ 文件中实现了 function:

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

NOTE: uart3 is an object of my Uart class.注意:uart3 是我的Uart class 的 object。 Hence it's C++ code.因此它是 C++ 代码。 I suspect this is the problem, but I can't figure out how to correct my error.我怀疑这是问题所在,但我不知道如何纠正我的错误。 Adding extern "C" to the function doesn't seem to solve it either.extern "C"添加到 function 似乎也不能解决它。

The linker error I get:我得到的 linker 错误:

Linking .pio\build\nucleo_f446ze\firmware.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
*** [.pio\build\nucleo_f446ze\firmware.elf] Error 1

What am I doing wrong?我究竟做错了什么?

UPDATE更新

The error I get when I declare the function as extern "C"当我将 function 声明为 extern "C" 时出现的错误

在此处输入图像描述

UPDATE 2:更新 2:

This does compile:这确实编译:

#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, ...);

You need to tell it to make the name C-linker compatible the first time it is seen.您需要告诉它在第一次看到它时使名称 C-linker 兼容。

update更新

The extern "C" is only when compiling as C++. extern "C"仅在编译为 C++ 时。 It is not legal syntax in C. C 中的语法不合法。 You can use extern by itself (it is implied if you leave it off).您可以单独使用extern (如果您不使用它,则暗示它)。

Editorial社论

That's not very friendly... C++ accommodates sharing header files with C by accepting syntax that would not apply to C++, just to make it easy to use the same header file contents. That's not very friendly... C++ accommodates sharing header files with C by accepting syntax that would not apply to C++, just to make it easy to use the same header file contents. In particular, using (void) for empty parameter lists (which is "an abomination") and allowing a comma in variadic function parameter lists ( (int x...) is how C++ originally defined it; when the same feature got incorporated into ANSI C they used (int x, ...) with a superfluous comma that is not needed by the grammar.) C++ compilers accept both of these to make it easier to consume C headers...特别是,将(void)用于空参数列表(这是“可憎的”)并允许在可变参数 function 参数列表中使用逗号( (int x...)是 C++ 最初定义它的方式;当相同的功能被合并到他们使用的ANSI C (int x, ...)带有语法不需要的多余逗号。)C++ 编译器接受这两者,以便更容易使用 Z0D61F8370CAD1D412F80B84D14 头文件...

But, you have to add extern "C" around everything.但是,您必须在所有内容周围添加extern "C" This introduces conditional compilation anyway, even though C++ accepts the C syntax.这无论如何都会引入条件编译,即使 C++ 接受 C 语法。 Note that for a single declaration, extern int foo (int);请注意,对于单个声明, extern int foo (int); the extern is allowed and implied if you leave it out.如果您将其排除在外,则extern是允许的并且是隐含的。 If the C compiler allowed the linkage specification even though only "C" is available, it would make life easier.如果 C 编译器允许链接规范,即使只有“C”可用,它也会使生活更轻松。 Note that in most cases, the C and C++ implementation are the same compiler suite, and often one language supports some features of the other as extensions.请注意,在大多数情况下,C 和 C++ 实现是相同的编译器套件,并且通常一种语言支持另一种语言的某些功能作为扩展。 It would be cool if gcc etc. supported extern "C++" in C mode, since that code base certainly does know how the name encodes the parameters.如果gcc等在 C 模式下支持extern "C++"会很酷,因为该代码库当然知道名称如何编码参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM