I've seen a related one here , but it's not the same answer.
Just as the title says, many of us know that the difference (both in features and syntax) between standards is quite large, ANSI C (C89, C90) did not allow many things that C99 onwards allows, such as the definition of a type in its declaration or the definition of a variable in a loop... Even one-line comments!
The question arises when having to make code that works under all C standards:
- ANSI C (C89 & C90)
- C94
- C99
- C11
Because I can't use the type long long
and some 8 and 16 bit platforms don't allow certain values causing integer overflow , likewise the compiler on these platforms is from when K&R (1972+) , others are from 1990, for what I don't have the new functionalities.
The best way to know which version of the standard you are compiling against is to use the preprocessor macro:
__STDC_VERSION__
, which is available as of C99 and its value is loaded with the following versions:__STDC_VERSION__ == 199409L
the standard isC94
1 .__STDC_VERSION__ == 199901L
the standard isC99
.__STDC_VERSION__ == 201112L
is standard isC11
.For other standards, preprocessor macros are defined:
__ANSI__
for ANSI C (C89 and C90)__STDC__
similarly for ANSI C 2 .A list of standards as of 2014 can be found:
Try the following program as an example:
When running it under the C99 standard:
I get the following result:
And if I compile it with a C++ compiler under the C11 standard:
The following result can be obtained:
Using that code you can tell which standard you are currently compiling, even with which compiler (Not its name, but the language) .
1 : This standard is not supported by
gcc
.2 : This macro is defined in all standards with the value of
1
, but its behavior can vary by compiler, so it is not totally reliable, unless you want to know if you are compiling with a C compiler, in a C compiler. C++ would not throw your definition.References:
As additional information I would like to add the C++ feature presence macros.
A brief section of history.
The 2011 C++ standard (initially known as C++0x and later known as C++11) was the slowest standard to be approved (the previous standard was from 1998 1 ).
C++11 added many new features to the C++ language, so many that it made C++ seem like a new language. Given the large number of features to be implemented by compiler developers, adherence to the C++11 standard was spotty and incomplete among compilers for a long time.
This made it necessary to be able to check individual language features rather than standards (since the compiler could claim to be C++11 but lack some C++11 features); To make this possible, feature presence macros were created.
Feature presence macros.
Feature presence macros allow you to check whether a particular C++ feature is implemented in the current C++ compiler.
Features are divided into library features and language features, so macros follow the format:
List of feature macros.
C++17__cpp_noexcept_function_type
: Make the exception specifications part of the function's signature. P0012R1 .__cpp_fold_expressions
: Groupable expressions. N4191 , N4295 .__cpp_static_assert
: Extension ofstatic_assert
. N3928 .__cpp_namespace_attributes
: Attributes for namespaces. N4196 , N4266 .__cpp_enumerator_attributes
: Attributes for enumerated.__cpp_nested_namespace_definitions
: Nested namespace definitions. N4230 .__cpp_inheriting_constructors
: Extension of legacy constructors. P0136R0 , P0136R1 .__cpp_nontype_template_args
: Allow constant evaluation of non-type template parameters. N4198 , N4268 .__cpp_lib_uncaught_exceptions
: Utilitystd::uncaught_exceptions
. N4152 , N4259 .__cpp_lib_as_const
: Utilitystd::as_const
. P0007R1 .__cpp_lib_transparent_operators
: Transparent operators (make it more flexiblestd::owner_less
). P0074R0 .__cpp_lib_invoke
: Utilitystd::invoke
. N4169 .__cpp_lib_void_t
: Utilitystd::void_t
. N3911 .__cpp_lib_bool_constant
: Utilitystd::bool_constant
. [N4389]8 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4389.html).__cpp_lib_type_trait_variable_templates
: Utilitystd::is_void_v
. P0006R0 .__cpp_lib_logical_traits
: Logical features. P0013R1 .__cpp_lib_chrono
: Rounding functions forstd::chrono::duration
andstd::chrono::time_point
. P0092R1 .__cpp_lib_allocator_traits_is_always_equal
: Cleanup of the standard library, removal ofnoexcept
. N4258 .__cpp_lib_incomplete_container_elements
: Incomplete types for standard containers. N4510 .__cpp_lib_map_try_emplace
,__cpp_lib_map_try_emplace
,__cpp_lib_unordered_map_try_emplace
: Improvements to the insert interface instd::map::try_emplace
,std::map::insert_or_assign
and their equivalents instd::unordered_map
. N4279 .__cpp_lib_nonmember_container_access
: Uniform access to container utilities through free functions. N4280 .__cpp_lib_shared_mutex
: Shared mutex without time limit. N4508 .__cpp_lib_lock_guard_variadic
:std::lock_guard
Variadic utility. P0156R0 .__cpp_binary_literals
: Binary literals. N3472 .__cpp_init_captures
: Generalized captures in lambdas. N3610 , N3648 .__cpp_generic_lambdas
: generic lambdas. N3649 .__cpp_sized_deallocation
: Operatordelete
with size. N3778 .__cpp_constexpr
: Relax the limitations ofconstexpr
. N3652 .__cpp_decltype_auto
,__cpp_return_type_deduction
: Deduction of the return type in functions. N3638 .__cpp_aggregate_nsdmi
: Member initializers in aggregates. N3653 .__cpp_variable_templates
: Template variables. N3651 .__cpp_lib_integer_sequence
: Utilitystd::integer_sequence
. N3658 .__cpp_lib_exchange_function
: Utilitystd::exchange()
. N3668 .__cpp_lib_tuples_by_type
: Access tuple members by type. N3670 .__cpp_lib_tuple_element_t
: Utilitystd::tuple_element_t
. N3887 .__cpp_lib_make_unique
: Utilitystd::make_unique
. N3656 .__cpp_lib_transparent_operators
: Transparent operators (make it more flexiblestd::greater
). N3421 .__cpp_lib_integral_constant_callable
: Call operator instd::integral_constant
. N3545 .__cpp_lib_transformation_trait_aliases
: Utilities on transformation traits. N3655 .__cpp_lib_result_of_sfinae
: Grants for the SFINAE technique . N3462 .__cpp_lib_is_final
: Utilitystd::is_final
. LWG 2112 .__cpp_lib_is_null_pointer
: Utilitystd::is_null_pointer
. LWG 2247 .__cpp_lib_chrono_udls
,__cpp_lib_string_udls
: User-defined literals for header types<chrono>
and<string>
. N3642 .__cpp_lib_generic_associative_lookup
: Heterogeneous comparisons in associative containers. N3657 .__cpp_lib_null_iterators
: null iterators. N3644 .__cpp_lib_make_reverse_iterator
: Utilitystd::make_reverse_iterator
. LWG 2285 .__cpp_lib_robust_nonmodifying_seq_ops
: Provide greater robustness to operations on a sequence that do not modify it (std::mismatch
,std::equal
andstd::is_permutation}
). N3671 .__cpp_lib_complex_udls
: User-defined literals for the typestd::complex
. N3779 .__cpp_lib_quoted_string_io
: Utilitystd::quoted
. N3654 .__cpp_lib_shared_timed_mutex
: Utilitystd::shared_timed_mutex
. N3891 .__cpp_unicode_characters
,__cpp_raw_strings
,__cpp_unicode_literals
: Unicode and raw text. N2249 . N2442 .__cpp_user_defined_literals
: User-defined literals. N2765 .__cpp_lambdas
: Lambdas. N2927 .__cpp_constexpr
: Constant expressions. N2235 .__cpp_range_based_for
for
: Range loop . N2930 .__cpp_static_assert
: Static assertions. N1720 .__cpp_decltype
: Type query operatordecltype
. N2343 .__cpp_attributes
: C++ attributes. N2761 .__cpp_rvalue_references
: References to values on the right side. N2118 .__cpp_variadic_templates
: Variadic templates. N2242 .__cpp_initializer_lists
: Initialization lists. N2672 .__cpp_explicit_conversion
: Explicit conversion operators. N2437 .__cpp_delegating_constructors
: Delegated constructors. N1986 .__cpp_nsdmi
: Initialization of non-static member data. N2756 .__cpp_inheriting_constructors
: Legacy constructors. N2540 .__cpp_ref_qualifiers
: Reference qualifiers. N2439 .__cpp_alias_templates
: Template aliases. N2258 .1 There is an unofficial standard in 2003 known as C++03 which was not actually a standard per se but a collection of technical specifications.