简体   繁体   English

可移植地识别非标准C ++?

[英]Recognize non-standard C++ portably?

C has __STDC__ but there seems to be no standard way of recognizing some extended C++ dialect. C具有__STDC__但是似乎没有识别某些扩展C ++方言的标准方法。 Hence for portable code I use 因此,对于便携式代码,我使用

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

This works for gcc, XLC and Visual C++ so far. 到目前为止,它适用于gcc,XLC和Visual C ++。

We have to test ISO/ANSI conformity idiosyncratically per compiler, right? 我们必须每个编译器都特质地测试ISO / ANSI一致性,对吗? If so, can you make suggestions for other compilers that have proven to work? 如果是这样,您能为其他证明有效的编译器提出建议吗?

EDIT: Since there was so much discussion about the for and against of such tests, here's a real world example. 编辑:由于关于此类测试的赞成和反对的讨论太多,所以这里有一个真实的例子。 Say there is some header stuff.h used widely with multiple compilers in multiple projects. 假设有一些标头stuff.h在多个项目中的多个编译器中广泛使用。 stuff.h uses some compiler-specific vsnprintf (not standardized before C++11), some copy_if<> ( they somehow missed it in C++98), own mutex guards and what not else. stuff.h使用一些特定于编译器的vsnprintf (在C ++ 11之前未标准化),一些copy_if<>他们在C ++ 98中以某种方式错过了它),自己的互斥保护以及其他功能。 While implementing a clean C++11 variant you wrap the old (but trusted) implementation in some #if __is_extended (better: __is_idosyncratic or !__is_ANSI_C11 ). 在实现干净的C ++ 11变体时,您将旧的(但受信任的)实现包装在一些#if __is_extended (更好的是__is_idosyncratic!__is_ANSI_C11 )。 The new C++11 goes behind an #else . 新的C ++ 11在#else When a translation unit that still compiles as C++0x or C++98 includes stuff.h nothing changed. 当仍可编译为C ++ 0x或C ++ 98的翻译单元包含stuff.h时,则保持不变 No compilation errors, no different behaviors at runtime. 没有编译错误,在运行时没有其他行为。 The C++11 remains experimental. C ++ 11仍处于试验阶段。 The code can be safely committed to the main branch, co-workers can study it, learn from it and apply techniques with their components. 可以将代码安全地提交给主分支,同事可以对其进行研究,学习并在其组件中应用技术。

Your question is actually backward, because the non-standard extensions supported by a compiler are specific to that compiler - often to the extent of being specific to a particular compiler version - as are the non-standard macros each compiler defines so they can be detected. 您的问题实际上是向后的,因为编译器支持的非标准扩展是特定于该编译器的-通常在某种程度上特定于特定的编译器版本-每个编译器定义的非标准宏也是如此,以便可以检测到它们。

The usual technique is the reverse: specify some feature you want, associate it with some macro, and only write code which uses that feature if the associated macro is defined. 通常的方法是相反的:指定所需的某些功能,将其与某个宏关联,如果定义了关联的宏,则仅编写使用该功能的代码。

Let's say there is some funky feature that is supported - in exactly the same way by Visual C++ 11 and g++ version 3.2.1, but not with any other compilers (not even other versions of Visual C++ or g++). 假设有一些受支持的时髦功能-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

There are plenty of freely available general purpose libraries which use this sort of technique (obviously with better naming of macros). 有很多免费的通用库都使用这种技术(显然,宏的命名更好)。 One example that comes to mind is the ACE (Adaptive Communication Environment) framework which has a set of portability macros, documented here . 我想到的一个例子是ACE(自适应通信环境)框架 ,该框架具有一组可移植宏, 在此处进行了介绍

Using such macros is not a job for the faint-hearted if you are concerned about a large set of non-standard features, given that it is necessary to understand what versions of what compilers (or libraries) support each feature, and to update the macros every time a new compiler, a new library, or even a patch is released. 如果您担心大量的非标准功能,那么使用这种宏对于胆小的人来说并不是一件容易的事,因为有必要了解哪些编译器(或库)的哪个版本支持每个功能,并更新它们。每次发布新的编译器,新的库甚至是修补程序时,都会使用这些宏。

It is also necessary to avoid using reserved identifiers in naming those macros, and to ensure the macro names are unique. 还必须避免在命名这些宏时使用保留的标识符,并确保宏名称是唯一的。 Identifiers starting with a double underscore are reserved. 保留以双下划线开头的标识符。

In general this will be hard to do because if you're relying on a non-conformant compiler then there's no standardized way to require only standard rules (the behavior of a non-standard compiler is not specified by the standard). 通常,这很难做到,因为如果您依赖的是不合格的编译器,那么就没有标准化的方法来只要求标准规则(标准未指定非标准编译器的行为)。

What you could do is adding an extra build step or commit hook and pass the code ALSO through a specific portable compiler (like g++) with specific strict conformancy options. 您可以做的是添加一个额外的构建步骤或提交挂钩,并通过具有特定严格一致性选项的特定可移植编译器(如g ++)传递代码ALSO。

First, you are not allowed to name variables in such way ( #define __is_extended ) because names beginning with two underscores are reserved for the implementation. 首先,不允许以这种方式命名变量( #define __is_extended ),因为为实现保留了以两个下划线开头的名称。

The method you have is still compiler-dependent and could fail: apart from __cplusplus , none of those macros are standard and therefore the implementation is not required to define them. 您拥有的方法仍然依赖于编译器,并且可能会失败:除了__cplusplus之外,这些宏都不是标准的,因此不需要实现即可定义它们。 Moreover, that test is basically checking what compiler is being used not whether or not some extensions are being used. 此外,该测试主要是检查的编译器正在使用的不在于是否正在使用一些扩展。

My advice is simply not to use extensions. 我的建议是不要使用扩展名。 There's very very little need for them. 他们几乎没有需要。 If you still want to make sure they don't get used anyway, you may turn your compiler's flags to restrict the usage of extensions; 如果仍然要确保它们不会被使用,则可以打开编译器的标志来限制扩展的使用。 for GCC, there's a whole chapter about this in the section "Options Controlling C Dialect" . 对于GCC,在“控制C语言的选项”部分中有整整一章。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM