目录
unknown type name '__declspec'
unknown type name '__declspec'
最近搞一个跨平台项目,在 Linux 下使用别人的库时发现别人头文件是这么写的:
#if defined SAPCLASSBASIC
#define SAPCLASSBASIC_VAR __declspec(dllexport)
#define SAPCLASSBASIC_CLASS __declspec(dllexport)
#else
#define SAPCLASSBASIC_VAR __declspec(dllimport)
#define SAPCLASSBASIC_CLASS __declspec(dllimport)
#endif
编译时出现很多错误,其中有:unknown type name '__declspec'
其实,__declspec 是 windows 专属,在 Linux 下,如果使用 GCC 就不能这样写,写法如下:
#if defined(_MSC_VER)
// Microsoft
#define EXPORT __declspec(dllexport)
#define IMPORT __declspec(dllimport)
#elif defined(__GNUC__)
// GCC
#define EXPORT __attribute__((visibility("default")))
#define IMPORT
#else
// do nothing and hope for the best?
#define EXPORT
#define IMPORT
#pragma warning Unknown dynamic link import/export semantics.
#endif
__declspec(dllexport) 替换成 __attribute__((visibility("default"))) , __declspec(dllimport) 替换成 空 即可。
下面是比较全面的写法和用法:
#if defined _WIN32 || defined __CYGWIN__
#ifdef BUILDING_DLL
#ifdef __GNUC__
#define DLL_PUBLIC __attribute__ ((dllexport))
#else
#define DLL_PUBLIC __declspec(dllexport) // Note: actually gcc seems to also supports this syntax.
#endif
#else
#ifdef __GNUC__
#define DLL_PUBLIC __attribute__ ((dllimport))
#else
#define DLL_PUBLIC __declspec(dllimport) // Note: actually gcc seems to also supports this syntax.
#endif
#endif
#define DLL_LOCAL
#else
#if __GNUC__ >= 4
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
#define DLL_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define DLL_PUBLIC
#define DLL_LOCAL
#endif
#endif
extern "C" DLL_PUBLIC void function(int a);
class DLL_PUBLIC SomeClass
{
int c;
DLL_LOCAL void privateMethod(); // Only for use within this DSO
public:
Person(int _c) : c(_c) { }
static void foo(int a);
};
详细见:http://gcc.gnu.org/wiki/Visibility
unknown type name 'class'
然后 __declspec 的错误没有了,接着又发生了 unknown type name 'class' 错误,这是因为我的编译环境自动使用的是 gcc 来编译的,程序文件都是 .c 结尾的,我将 .c 改为 .cpp 即可。
原因:当 c 使用 c++ 头文件时,C 文件 include 了带有 C++ 关键字的头文件,如 class 等。因此,包含 C++ 关键字的头文件被 C 编译器所编译,而不是用 C++ 编译器编译,而 C 编译器无法识别 C++ 的关键字,所以报错。
解决方法:
1、最好不要在 C 文件中包含 C++ 的头文件,建议将 .c 改成 .cpp
2、在所有使用 C++ 方法的地方加上:#ifdef __cplusplus,如:
#ifdef __cplusplus
class A{
};
#endif
注意:如果 c++ 文件中使用了 extern "C" ,我们要另外声明,因为 C 中是没有 extern "C" 的:
//C++头文件 cppExample.h
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add( int x, int y );
#endif
/* C实现文件 cFile.c */
extern int add( int x, int y );
int main( int argc, char* argv[] )
{
add( 2, 0 );
return 0;
}
extern "C" 的作用
被 extern "C" 修饰的变量和函数是按照 C 语言方式编译和链接的,关于 c 和 c++ 的编译链接的不同之处暂且不做讨论。
在标准 C 的头文件中,经常看到如下版本:
#ifndef __FILE_H /*防止该头文件被重复引用*/
#define __FILE_H
#ifdef __cplusplus //__cplusplus是cpp中自定义的一个宏
extern "C" { //告诉编译器,这部分代码按C语言的格式进行编译,而不是C++的
#endif
/**** some declaration or so *****/
#ifdef __cplusplus
}
#endif
#endif /* __FILE_H */
所以,我们在写 C 文件时,考虑到使用者有可能是 C++ 用户,最好要加上这样的标注。还有如下应用场合:
当我们使用 C++ 编程,需要引用 C 库和其头文件,那么我们在 C++ 文件中应该这么写:
#ifndef __CPP_FILE_H /* cpp 头文件 */
#define __CPP_FILE_H
extern "C"
{
#include "cExample.h"
}
#endif /* __CPP_FILE_H */