问题描述
我正在开发一个我希望可以移植的C应用程序。在Linux上使用gcc和clang,在Windows上使用MSVC可以很好地构建它。访问Mac之后,我尝试使用命令行工具进行构建。
它无法编译,因为我的代码声明了一个函数isnumber
,而Apple的ctype.h
标头也声明了一个(非标准的)isnumber
。我可以重命名函数,这样就不会发生冲突,但是有没有办法通过禁用或忽略所有或特定于Apple的标准标头添加项来避免这种情况呢?例如。是否有编译器选项或预处理器实用程序忽略它们?
我的isnumber
无法检查字符类。下面是重现此问题的代码-它可以使用clang / Linux和MSVC / Windows进行编译,但不能在Mac上编译(-实际代码不是)。
#include <ctype.h>
#include <stdio.h>
char *isnumber(void);
int main(void)
{
char *opt = "A";
if (isupper(*opt))
printf("THE IS NUMBER IS: %s\n",isnumber());
else
printf("The IS number is: %s\n",isnumber());
return 0;
}
char *isnumber(void)
{
return "IS-123";
}
错误:
/Users/ ... /repro/main.c:4:7: error: conflicting types for 'isnumber'
char *isnumber(void);
^
/Library/Developer/CommandLinetools/SDKs/MacOSX.sdk/usr/include/_ctype.h:323:1: note: prevIoUs deFinition is here
isnumber(int _c)
更新:
正如Acorn的回答及其注释所描述的那样,'isnumber'是函数的BAD名称,因为C11标准保留了它:
7.31将来的图书馆指南
为了方便起见,以下名称分组在各个标题下。 下面描述的所有外部名称都是保留的,无论程序包含什么标题。...
7.31.2字符处理
<ctype.h>
“可以将is
或to
开头的函数名称以及小写字母添加到<ctype.h>
标头中的声明中。”
所以对我的原始问题的“正确”解决方案是让我重命名 my 函数。
解决方法
我正在开发一个我希望可移植的C应用程序。
由于我的代码声明了函数
,因此无法编译isnumber
C和POSIX都保留所有is[a-z]*
名称(仅在包含标头的情况下才是POSIX),因此代码不可移植。
使其具有可移植性的唯一方法是避免使用此类标识符。
一种解决方案是在您提到的该规范中添加所有与该规范名称类似的标识符作为前缀。 xx*
或xx_*
。 C库采用了类似的方法来避免与其他库的冲突。
非解决方案包括:
- 避免包含
ctype.h
。即使在实践中,它仍具有不便携性,即使在其他系统中工作的可能性更高。 - 使用某些宏定义禁用扩展。仍然不能移植,因为其他系统可能无法识别并仍然定义
isnumber
。在实践中,您最终将不得不研究如何在每个系统中执行类似的操作。
是的,可以将其禁用。但是在禁用任何内容之前,我强烈建议阅读Acorn的答案。仅仅因为您可以禁用它们,并不意味着您应该这样做。例如,在我的案例中,尝试禁用Apple附加功能是错误解决方案。但是我的问题是“可以...”而不是“应该...”。
可以通过在#define _POSIX_C_SOURCE
之前添加#define _ANSI_SOURCE
或#include ctype.h
来禁用它们。这将“禁用” Apple附加程序到库中,例如:
#define _POSIX_C_SOURCE
#include <ctype.h>
#include <stdio.h>
...
如果仅在maxOS上定义时,可以先检查系统定义的宏__MACH__
(请参阅this question),例如:
#ifdef __MACH__
#define _POSIX_C_SOURCE
#endif
#include <ctype.h>
#include <stdio.h>
...
说明:
Apple的ctype.h
包括_ctype.h
,其中附加的声明和定义由以下内容保护:
#if !defined(_ANSI_SOURCE) && (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
谢谢FelixG,他首先指出了我的方向。