C头文件宏

C头文件宏,c,C,如果我为供应商(需要实现这些接口的供应商)创建接口,为什么要在API中使用上述声明?我认为它被称为一个宏——为什么我不能像“normal”那样声明函数呢?:int M_Process()?区别是什么?上面声明的各个部分做了什么?像这样的宏主要是为了与不同的C编译器兼容而添加的。您可以在20世纪80年代和90年代的代码中找到这一点,这些代码适用于兼容K&R(早于ANSI C)或缺乏各种功能的编译器 您必须阅读宏定义才能绝对确定,但这类东西有一些常见的模式。宏分为几种类型: 联系公约 通过定义ML_

如果我为供应商(需要实现这些接口的供应商)创建接口,为什么要在API中使用上述声明?我认为它被称为一个宏——为什么我不能像“normal”那样声明函数呢?:
int M_Process()?区别是什么?上面声明的各个部分做了什么?

像这样的宏主要是为了与不同的C编译器兼容而添加的。您可以在20世纪80年代和90年代的代码中找到这一点,这些代码适用于兼容K&R(早于ANSI C)或缺乏各种功能的编译器

您必须阅读宏定义才能绝对确定,但这类东西有一些常见的模式。宏分为几种类型:

联系公约 通过定义
ML_EXTERN
,API可以支持不同的(例如stdcall、fastcall等)或不同类型的外部链接(例如Microsoft的)。这提供了编译器兼容性和跨平台兼容性,同时不会严重影响代码的可读性

一致的类型大小
int
short
long
等类型中的位数取决于平台,尽管存在一些限制。许多早于标准
inttypes.h
stdint.h
头的库使用宏或typedef来确保它们的类型在所有平台上的大小相同
ML_INT
是一个宏,或者是一个大小适当的整数类型的typedef

原型支持 80年代的许多编译器是按照C的K&R标准构建的,不支持ANSI函数原型。
ML_FUNC
ML_ARGS_列表
宏解决了这个问题

如果支持原型,则将定义
ML\u ARGS\u LIST
,并且
ML\u FUNC(x)
将扩展到
x
。忽略
ML\u EXTERN
\u ML\u AB
的完整扩展将是:

ML_EXTERN _ML_AB ML_FUNC(M_Process)
#ifdef ML_ARGS_LIST
(
  ML_INT i
);
#endif
M_Process(ML_INT i)
如果编译器不支持原型,则
ML_FUNC(x)
将扩展到
x()
并将commited prototype参数列表。全面扩展将是:

ML_EXTERN _ML_AB ML_FUNC(M_Process)
#ifdef ML_ARGS_LIST
(
  ML_INT i
);
#endif
M_Process(ML_INT i)

在K&rc中,所有参数都是根据规则强制的,参数变量是在定义函数的地方定义的,而不是在声明函数的地方定义的。有关C版本差异的一些详细信息,请参阅。

像这样的宏主要是为了与不同的C编译器兼容而添加的。您可以在20世纪80年代和90年代的代码中找到这一点,这些代码适用于兼容K&R(早于ANSI C)或缺乏各种功能的编译器

您必须阅读宏定义才能绝对确定,但这类东西有一些常见的模式。宏分为几种类型:

联系公约 通过定义
ML_EXTERN
,API可以支持不同的(例如stdcall、fastcall等)或不同类型的外部链接(例如Microsoft的)。这提供了编译器兼容性和跨平台兼容性,同时不会严重影响代码的可读性

一致的类型大小
int
short
long
等类型中的位数取决于平台,尽管存在一些限制。许多早于标准
inttypes.h
stdint.h
头的库使用宏或typedef来确保它们的类型在所有平台上的大小相同
ML_INT
是一个宏,或者是一个大小适当的整数类型的typedef

原型支持 80年代的许多编译器是按照C的K&R标准构建的,不支持ANSI函数原型。
ML_FUNC
ML_ARGS_列表
宏解决了这个问题

如果支持原型,则将定义
ML\u ARGS\u LIST
,并且
ML\u FUNC(x)
将扩展到
x
。忽略
ML\u EXTERN
\u ML\u AB
的完整扩展将是:

ML_EXTERN _ML_AB ML_FUNC(M_Process)
#ifdef ML_ARGS_LIST
(
  ML_INT i
);
#endif
M_Process(ML_INT i)
如果编译器不支持原型,则
ML_FUNC(x)
将扩展到
x()
,并将显示原型参数列表。全面扩展将是:

ML_EXTERN _ML_AB ML_FUNC(M_Process)
#ifdef ML_ARGS_LIST
(
  ML_INT i
);
#endif
M_Process(ML_INT i)

在K&rc中,所有参数都是根据规则强制的,参数变量是在定义函数的地方定义的,而不是在声明函数的地方定义的。有关C版本差异的一些详细信息,请参阅。

这样的宏允许根据平台注入调用约定和其他类型的链接装饰(例如库导入/导出)。例如,当你编译库本身时,你会注入一个“导出”修饰,而当你编译客户机代码时,它会是一个“导入”修饰。@KerrekSB你介意发布一个答案并用每个示例进行解释吗?我想您是说,对于应用程序开发人员来说,在编译代码时会“注入导入装饰”。对于实现此API的供应商,您在编译代码时会“注入导出装饰”。然而,我不明白这是如何工作的(“注入装饰”是什么样子的?)或者为什么你需要这个声明来做这件事。作为一名应用程序开发人员,我通常会简单地#包含头文件,然后从头文件定义函数。谢谢你的发帖。@KyleM我认为这对应用程序开发人员来说并不像对库开发人员处理X编译器库导出那样重要。@KerrekSB如果你没有时间做一个例子,你知道我应该找什么样的教程/文章吗?或者这叫什么样的设计模式?@KyleM通常你会看到一些东西的本质<代码>如果VC(定义导出\uuuuExportVC)如果GCC(定义导出\uuuExportGCC)外部导出myFunc()每个编译器的关键字不同,此格式允许您通过重新定义导出宏轻松处理编译器差异。类似于此的宏允许平台相关的调用约定注入和其他类型的链接装饰(例如库im