C 有__STDC__
,但似乎没有标准方法来识别某些扩展的C ++方言。因此对于便携式代码,我使用
#define __is_extended \
((__GNUG__ &&!__STRICT_ANSI__) || \
(_MSC_VER && _MSC_EXTENSIONS && __cplusplus) || \
(__IBMCPP__ && __EXTENDED__))
到目前为止,这适用于gcc,XLC和Visual C ++。
我们必须每个编译器特异性地测试ISO / ANSI一致性,对吧?如果是这样,你能为其他已证明有效的编译器提出建议吗?
编辑:由于关于此类测试的支持和反对的讨论非常多,这里有一个真实的例子。假设有一些标题 stuff.h 在多个项目中广泛用于多个编译器。 stuff.h 使用一些特定于编译器的vsnprintf
(在C ++ 11之前未标准化),一些copy_if<>
(they somehow missed在C ++ 98中),拥有互联网守卫,什么不是。在实现干净的C ++ 11变体时,您将旧的(但可信的)实现包装在某些#if __is_extended
中(更好:__is_idosyncratic
或!__is_ANSI_C11
)。新的C ++ 11落后于#else
。当仍然编译为C ++ 0x或C ++ 98的翻译单元包含 stuff.h 时,没有任何改变。没有编译错误,在运行时没有不同的行为。 C ++ 11仍然是实验性的。代码可以安全地提交给主分支,同事可以研究它,从中学习并使用其组件应用技术。
答案 0 :(得分:2)
您的问题实际上是向后的,因为编译器支持的非标准扩展特定于该编译器 - 通常是特定于特定编译器版本的程度 - 每个编译器定义的非标准宏也是如此可以被发现。
通常的技术是相反的:指定您想要的某些功能,将其与某个宏关联,并且只有在定义了相关宏的情况下才编写使用该功能的代码。
让我们说有一些时髦的功能得到支持 - 以完全相同的方式被Visual C ++ 11和g ++版本3.2.1支持,但没有任何其他编译器(甚至没有其他版本的Visual C ++或g ++) )。
// in some header that detects if the compiler supports all sorts of features
#if ((defined(__GNUG__) && __GNUC__ == 3 && __GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ == 1) || (defined(_MSC_VER) && _MSC_VER == 1700))
#define FUNKY_FEATURE
#endif
// and, in subsequent user code ....
#ifdef FUNKY_FEATURE
// code which uses that funky feature
#endif
有许多免费提供的通用库使用这种技术(显然有更好的宏命名)。我想到的一个例子是ACE (Adaptive Communication Environment) framework,它有一组可移植性宏,记录在案here。
如果您关注大量非标准功能,那么使用这些宏并不适合胆小的人,因为有必要了解哪些编译器(或库)支持每个功能的版本,以及每次发布新编译器,新库甚至补丁时都要更新宏。
还必须避免在命名这些宏时使用保留标识符,并确保宏名称是唯一的。以双下划线开头的标识符将被保留。
答案 1 :(得分:1)
一般来说,这很难做到,因为如果你依赖的是不符合标准的编译器,那么就没有标准化的方法只需要标准规则(标准没有指定非标准编译器的行为)。
你可以做的是添加额外的构建步骤或提交钩子,并通过具有特定严格的一致性选项的特定可移植编译器(如g ++)传递代码。
答案 2 :(得分:0)
首先,不允许以这种方式命名变量(#define __is_extended
),因为以两个下划线开头的名称是为实现保留的。
您拥有的方法仍然依赖于编译器并且可能会失败:除了__cplusplus
之外,这些宏都不是标准的,因此不需要实现来定义它们。此外,该测试基本上是检查正在使用的编译器,而不是某些扩展是否正在使用。
我的建议是不要使用扩展程序。对他们的需求非常小。如果你仍然想确保它们不被使用,你可以转动你的编译器标志来限制扩展的使用;对于GCC,在"Options Controlling C Dialect"部分中有关于此的整章。