终止“ C”或不终止“ C” [g ++ vs cl]

时间:2019-01-25 17:03:23

标签: c++ c g++ cl extern-c

我正在比较数字食谱four1.c与Nayuki's FFT。两者都是C版本,但我使用的是C ++驱动程序。为了进行比较,我将使用CL.exe和g ++将它们都编译(或更恰当地,链接)成一个可执行文件。两者似乎正在为是否要对four1函数使用extern“ C”进行争执,但似乎都不在乎Nayuki的想法。我为four1创建了一个头文件,该文件检查_WIN32以进行适当的切换,并且它可以工作,但似乎是完全不可接受的黑客。我该如何解决?

这是头文件:

#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

如果使用extern“ C”,这就是g ++的作用:

/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 ++无效。

2 个答案:

答案 0 :(得分:6)

查看几乎所有系统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 ++的标题中遵循的模式。当然,除了您不应使用前划线,因为它们是为系统内容保留的。

答案 1 :(得分:0)

使用gcc编译four1.c g++