3

我将数字食谱four1.c 与Nayuki 的FFT进行比较。两者都是 C 版本,但我使用的是 C++ 驱动程序。为了进行比较,我正在使用 CL.exe 和 g++ 将两者编译(或更恰当地说,链接)到可执行文件中。两人似乎在争论是否将 extern "C" 用于four1 函数,但似乎都不关心Nayuki 的。我为four1 制作了一个头文件,它检查_WIN32 以便适当地切换,它可以工作,但似乎是一个完全不可接受的hack。我将如何解决这个问题?

这是头文件:

#pragma once
#ifdef _WIN32
extern "C" void four1(float data[], unsigned long nn, int isign);
#else
void four1(float data[], unsigned long nn, int isign);
#endif

这就是 CL 在没有外部“C”的情况下所做的:

drvr.obj : error LNK2019: unresolved external symbol "void __cdecl four1(float * const,unsigned long,int)" (?four1@@YAXQAMKH@Z) referenced in function _main
drvr.exe : fatal error LNK1120: 1 unresolved externals

这就是 g++ 在使用 extern "C" 时所做的:

/tmp/ccK1Hb2N.o: In function `main':
drvr.cpp:(.text+0x347): undefined reference to `four1'
collect2: error: ld returned 1 exit status

对 CL 有效的对 g++ 无效,对 g++ 有效的对 CL 无效。至少对于这个文件。Nayuki 代码不存在这样的问题。

我尝试按照建议修改头文件,所以现在是 dfour1.h:

#pragma once
/* C++ needs to know that types and declarations are C, not C++.  */
#ifdef  __cplusplus
# define __BEGIN_DECLS  extern "C" {
 void dfour1(double data[], unsigned long nn, int isign);
# define __END_DECLS    }
#else
# define __BEGIN_DECLS
# define __END_DECLS
#endif

g++ 很好。CL 不是。

>cl drvr.cpp dfour1.c fft.c carrier.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

drvr.cpp
Generating Code...
Compiling...
dfour1.c
fft.c
Generating Code...
Compiling...
carrier.cpp
Generating Code...
Microsoft (R) Incremental Linker Version 14.00.24215.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:drvr.exe
drvr.obj
dfour1.obj
fft.obj
carrier.obj
drvr.obj : error LNK2019: unresolved external symbol "void __cdecl dfour1(double * const,unsigned long,int)" (?dfour1@@YAXQANKH@Z) referenced in function _main
drvr.exe : fatal error LNK1120: 1 unresolved externals

顺便说一句,如果没有头文件,也会发生同样的情况,我只需添加:

extern "C" void dfour1(double data[], unsigned long nn, int isign);

到 drvr.cpp 文件,并删除头文件。CL 仅在extern "C"存在时才有效,但 g++ 则无效。而删除extern "C"适用于 g++ 但不适用于 CL。

是的,我知道原始头文件是错误的,这就是问题的重点。当我“正确”地做到这一点时,它不起作用,因此是帖子。当我制作了一个“不正确”的头文件来检查正在使用的编译器时,它起作用了,这是令人讨厌的部分。简单地检查 c++ 是行不通的。

4

2 回答 2

7

查看几乎所有系统 C 头文件,您会看到如下代码:

/* C++ needs to know that types and declarations are C, not C++.  */
#ifdef  __cplusplus
# define __BEGIN_DECLS  extern "C" {
# define __END_DECLS    }
#else
# define __BEGIN_DECLS
# define __END_DECLS
#endif

__BEGIN_DECLS

// some declarations

__END_DECLS

这是在您需要接口 C 和 C++ 的您自己的标头中遵循的模式。当然,除非您不应该使用前导下划线,因为它们是为系统内容保留的。

于 2019-01-25T17:37:40.620 回答
1

用来gcc编译four1.c不是 g++

于 2019-04-09T16:43:03.997 回答