可移植地识别非标准c++

Recognize non-standard C++ portably?

本文关键字:c++ 非标准 识别 可移植      更新时间:2023-10-16

C__STDC__,但似乎没有标准的方法来识别一些扩展的c++方言。因此对于可移植代码,我使用

#define __is_extended                                   
    ((__GNUG__   &&!__STRICT_ANSI__)  ||                
     (_MSC_VER   && _MSC_EXTENSIONS && __cplusplus)  || 
     (__IBMCPP__ && __EXTENDED__))

目前为止gcc, XLC和Visual c++都可以使用。

我们必须测试每个编译器的ISO/ANSI一致性,对吗?如果是这样,您能对其他已被证明有效的编译器提出建议吗?

编辑:既然有这么多关于支持和反对这样的测试的讨论,这里有一个真实世界的例子。假设有一些头文件的东西。h在多个项目的多个编译器中广泛使用。stuff.h使用一些编译器特定的vsnprintf(在c++ 11之前没有标准化),一些copy_if<>(在c++ 98中不知怎么错过了),自己的互斥锁保护等等。在实现一个干净的c++ 11变体时,您将旧的(但可信的)实现包装在一些#if __is_extended中(更好的是:__is_idosyncratic!__is_ANSI_C11)。新的c++ 11在#else之后。当翻译单元仍然编译为c++ 0x或c++ 98时,包含的东西。h没有任何变化。没有编译错误,运行时没有不同的行为。c++ 11仍然是实验性的。代码可以安全地提交给主分支,同事可以研究它,从中学习并将技术应用于他们的组件。

你的问题实际上是向后的,因为编译器支持的非标准扩展是特定于该编译器的-通常是特定于特定编译器版本的程度-每个编译器定义的非标准宏也是如此,因此它们可以被检测到。

通常的技术是相反的:指定一些你想要的特性,将其与一些宏关联,并且只有在关联的宏被定义的情况下才编写使用该特性的代码。

让我们假设有一些时髦的特性被支持-以完全相同的方式被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(自适应通信环境)框架,它有一组可移植性宏,在这里有文档。

如果你关心大量的非标准特性,使用这样的宏不是胆小的人的工作,因为有必要了解哪些版本的编译器(或库)支持每个特性,并在每次发布新的编译器、新的库甚至补丁时更新宏。

还必须避免在命名这些宏时使用保留标识符,并确保宏名称是唯一的。以双下划线开头的标识符是保留的。

一般来说,这很难做到,因为如果你依赖于一个不符合标准的编译器,那么就没有标准化的方法来只要求标准规则(标准没有指定非标准编译器的行为)。

你可以做的是添加一个额外的构建步骤或提交挂钩,并通过特定的可移植编译器(如g++)传递代码,并提供特定的严格一致性选项。

首先,不允许以这种方式(#define __is_extended)命名变量,因为以两个下划线开头的名称是为实现保留的。

您拥有的方法仍然依赖于编译器,并且可能失败:除了__cplusplus之外,这些宏都不是标准的,因此实现不需要定义它们。此外,该测试基本上是检查正在使用的编译器,而不是是否使用了一些扩展

我的建议就是不要使用扩展。对它们的需求非常非常少。如果你仍然想确保它们不会被使用,你可以改变编译器的标志来限制扩展的使用;对于GCC,在"选项控制C方言"一节中有一整章的内容。

相关文章: