在 gRPC 函数声明之前空宏 `GRPCAPI` 有什么影响?

What's the effect of empty macro `GRPCAPI` before gRPC function declaration?

当我阅读 gRPC 中的代码时,我发现许多 API 使用 GRPCAPI 作为限定符。

GRPCAPI grpc_channel* grpc_cronet_secure_channel_create(
    void* engine, const char* target, const grpc_channel_args* args,
    void* reserved);

当我点击 link 到 GRPCAPI 时,它是一个空宏。

#ifndef GPRAPI
#define GPRAPI
#endif

#ifndef GRPCAPI
#define GRPCAPI GPRAPI
#endif

了解空宏的一些用法:

但是这里的GRPCAPI两者都不属于。它只是一个标记来告诉我们函数是一个 API 吗?或者对文档或其他功能有更多影响?

它用于平台特定属性或未来属性。

对于 Windows 个 DLL,您通常指定
__declspec(dllexport)编译库
__declspec(dllimport) 消耗库时

宏是编译和使用宏的便捷方式,因为您只需在 header.[=32 中将宏的值定义为 __declspec(dllexport)/__declspec(dllimport) =] 其他编译器属性也是如此,例如 GCC

上的 __attribute__(visibility(default))/__attribute__(visibility(hidden))

现在,当静态链接库时,您不需要所有这些,您将宏定义为没有价值。
一个例子是:

#ifdef STATIC_LIBRARY
     #define LIBRARY_API 
#else
#ifdef LIBRARY_EXPORTS
#    define LIBRARY_API __declspec(dllexport)
#else
#    define LIBRARY_API __declspec(dllimport)
#endif


LIBRARY_API void foo(); // when statically linked, it's a simple void function. If dynamically linked, it's either dllexport when compiling the library or dllimport when consuming it.

另一种解释可能是调用约定修饰符。 x86(我只知道 x86)有不同的调用约定 - 这些决定了 caller/callee 如何在汇编级别处理函数的参数。

像这样:

#if WIN32
#define APICALL cdecl
#else
#define APICALL 
#endif

APICALL void foo() // uses cdecl on WIN32

非常感谢@Raildex 的回答和@paulsm4 的评论,非常鼓舞人心。

但是GRPCAPIGPRAPI的功能完全一样,都是用来标记API的标签。

grpc中有一个名为list_api.py的脚本使用了标签GPRAPI和GRPCAPI,这是唯一使用这两个标签的地方。

_RE_API = r'(?:GPRAPI|GRPCAPI|CENSUSAPI)([^;]*);'

for m in re.finditer(_RE_API, text):   # match file content
...

在 运行 脚本之后,我们将得到:

...
- arguments: void* engine, const char* target, const grpc_channel_args* args, void*
    reserved
  header: include/grpc/grpc_cronet.h
  name: grpc_cronet_secure_channel_create
  return_type: grpc_channel*
...