Different C++ Standards: The Story of C++

0
1428
c++ programming

C++ is a programming language very popular in academia and the industry. When a professor tries to cover a lot of topics within a short span of three to four months, it is natural to omit the history part of a programming language altogether. This may not be a good strategy in the long run, because to fully understand the intricacies and power of a programming language some knowledge of its history is absolutely essential. This article addresses the historic aspects of C++ and the different standards over the years. It serves as good supplementary reading material to students learning C++ for the first time.

First, let’s begin with the origin of C++ and also about the man behind it, Bjarne Stroustrup. C++ is one of the most popular programming languages in the world, and has been a permanent fixture in the top ten of every programming language popularity ranking scheme for many years. It is interesting to know that all the top four programming languages in the April 2021 ranking of the TIOBE Index were developed by individuals. They are: Dennis Ritchie (C), Guido van Rossum (Python), James Gosling (Java) and Bjarne Stroustrup (C++). All of them are superstars in the world of computer programming.

Nowadays programming languages are designed by a team of computer scientists and the credit goes to the parent organisation. But more than 30 years ago, the task was done by lone geniuses. Bjarne Stroustrup is a Danish computer scientist. While working at AT&T Bell Laboratories, he had many bright ideas to improve the ever popular C programming language. By the end of the 70s (a time when C was just celebrating its ninth birthday), Stroustrup presented his improvements to C. At first he considered this new language just as an extension to C and was modest enough to call it ‘C with Classes’. Soon, the new language started gaining the attention of serious programmers and by the early 80s people started considering it as a programming language independent of C.

The name C++ comes from the programming language C and the post-increment operator ‘++’ used in C as well as C++. The procedural programming features of C++ were influenced by C, and the object-oriented programming features of C++ were influenced by a programming language called Simula. For almost two decades, the de facto standard of C++ was set by the textbooks on C++ written by Bjarne Stroustrup. Finally, in 1998 came the first standard of C++ called C++98. C++11 and C++17 standards brought in several major changes and additions to the C++ language. In between C++03 and C++14 brought in minor changes. C++20 is the latest standard of C++, and as of now no compiler has full support for all the features mandated by this standard. The next standard of C++ is the proposed C++23. Though begun as an extension to C, C++ today is an object-oriented programming language with additional support for some functional programming features.

Now, let us discuss the different standards of C++ in detail. To enhance our understanding about each of these standards, we will also discuss small programs that demonstrate certain features and changes brought in by successive standards. But here comes an important question. What compiler are we going to use? There are many C++ compilers available depending on the operating system and the architecture being used. But from an open source software perspective the choices are obvious — g++ and clang++. The Clang compiler (invoked with the command clang++) from the LLVM compiler infrastructure project supports many of the latest features of C++. But we will use the very popular C++ compiler called g++, a part of GCC (GNU Compiler Collection), to compare the features offered and revoked by successive standards of C++. The choice not only depended on the popularity of g++ but also on the support for the latest features of C++. Here, again g++ was a winner over clang++. Of course there are areas where clang++ outperforms g++. But that discussion is for another day.

Before we proceed any further, we need to have an answer for the following question. What is the need for standardisation of programming languages? Imagine two software companies A and B designing compilers for C++. Company A decides to have 4 byte integers in its compiler. Without an accepted standard to adhere to, nothing stops company B from having a 40 byte integer in its compiler. And within no time, we will have two versions of C++ — C++A and C++B. So, it is always good to have standards on which compiler designers can rely. Now, let us begin our discussion of different C++ standards with the ‘Stroustrup Standard’ of C++.

The pre-98 ‘Bjarne Stroustrup’ standard
As mentioned earlier, Bjarne Stroustrup wanted to extend the C programming language, and by 1979 he was able to add features like classes, member functions, private and public access control, etc, to C. But soon after the language got the attention of professional programmers, around 1984, ‘C with classes’ was renamed as C++. By 1985, C++ was available outside Bell Labs. In 1985, a C++ textbook written by Bjarne Stroustrup called ‘The C++ Programming Language’ was first published. It instantly became the de facto standard of C++ and remained so until 1998. By 1985, C++ had additional features like virtual functions and operator overloading. In 1990, Margaret A. Ellis and Bjarne Stroustrup published a C++ manual called ‘The Annotated C++ Reference Manual’. This further helped the standardisation of C++. According to the C++ manual of 1990, C++ only has 48 keywords. Cfront 1.0, Cfront 2.0 and Cfront 3.0 are three C++ compilers for this version of C++ that existed before 1998. GCC version 1.15.3, released in 1987, started supporting C++.

Unfortunately, programs written in the pre-98 version of C++ cannot be tested any more as neither g++ nor clang++ has an option to compile such C++ programs. Now consider the C++ program pgm1.cc given below. Notice that this short program does not produce any output.

#include<iostream>
int main( )
{
struct str;
struct str;
return 0;
}

Both g++ and clang++ compile this program without any errors because only multiple definition of a variable causes an error in C++ (multiple declaration of a variable is fine). This rule is mentioned in the 1990 C++ manual. I believe this rule is a relic of the past and GCC being backward compatible to some extent is the only reason why such code is still tolerated. The compilation and execution steps of the program pgm1.cc using g++ as well as clang++ are given below.

>> g++ pgm1.cc
>> ./a.out
>> clang++ pgm1.cc
>> ./a.out

C++98 standard
The need for standardisation increased along with the rise in the popularity of C++. In 1991, ISO (International Organisation for Standardisation) formed an ISO C++ committee for standardisation. This committee was called WG21, officially ISO/IEC JTC1 (Joint Technical Committee 1) / SC22 (Subcommittee 22) / WG21 (Working Group 21). The first official standard, informally called C++98 (official document ISO/IEC 14882:1998), was finalised and adopted in 1998. Figure 1 shows the logo of C++ adopted by ISO.

The logo of C++ adopted by ISO
Figure 1: The logo of C++ adopted by ISO

Now, let us learn about the features of this first official C++ standard. Fifteen more keywords were added to the existing 48 keywords from the 1990 C++ manual, making the total number of keywords 63. The newly added keywords were bool, true, false, const_cast, dynamic_cast, reinterpret_cast, static_cast, using, namespace, typeid, typename, wchar_t, mutable, explicit and export. Further, there are 11 reserved alternative representations for certain operators and punctuators. They are and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor and xor_eq. Notice that they remain reserved in every subsequent standard of C++. Some of the important features introduced by C++98 include changes in type casting, introduction of Boolean operators and mutable class members, etc. There were modifications in the C++ Standard Library also. Though not explicitly mentioned in the official documents, the Standard Template Library (STL) offering algorithms, containers, functions, and iterators also influenced the C++98 standard. I believe that until the arrival of STL, most C++ programs could have been ported to C without much difficulty. But STL became a game changer and made C++ truly different from C.

Let us now focus on the g++ compiler. What is the default standard of the g++ compiler — C++98, C++03, C++11, C++14, C++17 or C++20? The answer is ‘None of these’. The default standard of g++ is C++XX with additional GNU specific features. Here, XX denotes a C++ standard and it depends on the version of GCC on your system. I have GCC 7.5.0 in my system and g++ defaults to C++14 with additional GNU specific features. But if you want to use a different standard, use the g++ option ‘-std=c++XX’ (XX denotes a specific standard of C++) which will compile the program by strictly following the rules set by the particular standard specified. For example, ‘g++ -std=c++98 pgm1.cc’ will compile the program pgm1.cc conforming to the C++98 standard. Similarly, the g++ option ‘-std=gnu++XX’ (XX denotes a specific standard of C++) will compile the program by the rules set by the particular standard specified along with GNU specific extensions. For example, ‘g++ -std=c++11 pgm1.cc’ will compile the program pgm1.cc conforming to the C++11 standard with GNU specific extensions. Now, consider the program pgm2.cc given below:

#include<iostream>
using namespace std;
int main( )
{
	int constexpr=98;
	cout<<”I am C++”<<constexpr<<endl;
	return 0;
}

The compilation and execution steps of the program pgm2.cc conforming to the C++98 standard are given below:

>> g++ -std=c++98 pgm2.cc
>> ./a.out
I am C++98
>> g++ -std=gnu++98 pgm2.cc
>> ./a.out
I am C++98
>> g++ -std=c++11 pgm2.cc
pgm2.cc: In function ‘int main()’:
pgm2.cc:5:15: error: expected unqualified-id before ‘=’ token
int constexpr=98;
^
pgm2.cc:6:20: error: expected primary-expression before ‘constexpr’
cout<<”I am C++”<<constexpr<<endl;
^~~~~~~~~

As you can see, the program successfully compiles and the message I am C++98 gets printed on the screen. We can also see that the g++ option ‘-std=gnu++98’ also results in the same output. But we can observe that the same program shows errors when compiled as a program conforming to the C++11 standard. Could you explain the reason?

C++03 standard
C++03 (official document ISO/IEC 14882:2003) was introduced in 2003. Compared to the previous version of C++, C++03 only introduced minor changes to the language. This also reflects the way C++ standards are released, in general. The release of every major C++ standard is followed by the release of a minor C++ standard. This minor standard is released mainly to address the shortcomings of the previous major release as well as for fixing bugs. No keywords were added or deprecated by C++03. The only new language feature added was value initialisation. This is the initialisation performed when an object is constructed with an empty initialiser. It is possible to use the g++ option ‘-std=c++03’ to make sure that a program conforms to the C++03 standard.

C++11 standard
C++11 (official document ISO/IEC 14882:2011) was introduced in 2011. C++11 is a major version of C++, and just like C++98 brought in a considerable amount of changes to the language. We will start our discussion by analysing the keywords. There are 73 keywords in C++11. The following 10 new keywords were added to the existing 63 keywords from C++98. They are alignas, alignof, constexpr, char16_t, char32_t, decltype, noexcept, nullptr, static_assert and thread_local.

Now, I hope you are able to explain the reason for the error shown in the output of the program pgm2.cc shown earlier. In C++11, constexpr is a keyword, whereas in C++98 it is not. The keyword constexpr allows functions to return constant expressions, which at compile time will lead to an optimisation whereby the function call is replaced with a constant value. C++11 also brought in lambda functions, thereby giving functional programming capabilities to C++. Thus C++ became a multi-paradigm programming language, at least to some extent. The keyword export was used to allow multiple declarations of templates in C++98 and C++03. In C++11, export was unused and reserved for future use. C++11 made several changes to the C++ Standard Library, and also introduced range-based for loops. Consider the program pgm3.cc given below:

#include<iostream>
using namespace std;
int main( )
{
        int arr[5] = {1, 2, 3, 4, 5};
        for (int& i: arr)
        {
                cout<<i*i<<” “;
        }
        cout<<endl;
        return 0;
}

The compilation and execution steps of the program pgm3.cc using a range-based for loop are given below. The program finds and outputs the squares of the numbers in the array arr.

>> g++ -std=c++11 pgm3.cc
>> ./a.out
1 4 9 16 25
>> g++ -std=c++98 pgm3.cc
pgm3.cc: In function ‘int main()’:
pgm3.cc:6:15: warning: range-based ‘for’ loops only available with -std=c++11 or -std=gnu++11
  for (int& i: arr)
                    ^~~
pgm3.cc:6:15: error: forming reference to reference type ‘int (&)[5]’

We can also observe that when the program is compiled with the g++ option, ‘-std=c++98’ gives an error. The same error would have appeared even if we compiled with the g++ option ‘-std=c++03’. The error is due to the fact that this feature was not available in versions older than C++11. I am not sure about C++ programmers, but seasoned Python programmers will definitely appreciate this type of for loop. Now let us move on to C++14.

C++14 standard
C++14 (official document ISO/IEC 14882:2014) was introduced in 2014. Just like C++03, C++14 also made minor changes to the language — mostly bug fixes to the C++11 implementation. No new keywords were added. Some of the features introduced by C++14 include variable templates, generic lambda functions, binary-literal 0b or 0B as integer suffix, etc. In C++14 also, the keyword export remained unused and reserved for future use. The g++ compiler claims full support for all the feature in C++ standards up to C++14. By using the g++ option ‘-std=c++14’, we can make sure that programs strictly conform to the C++14 standard.

C++17 standard
C++17 (official document ISO/IEC 14882:2017) was introduced in 2017. Though supposed to be a major version, compared to C++98 and C++11, C++17 introduced fewer number of changes to C++. No new keywords were added. In addition to the keyword export, the keyword register also is unused and reserved for future use in C++17. Some of the new features brought in by C++17 include lambda functions returning constant expressions, initialisers for if and switch statements, structured bindings, introduction of the u8 character literal, etc. There were some changes in the expression evaluation rules. For example, the statement ‘i = i++ + 1;’ would cause an undefined behaviour in standards prior to C++17. The somewhat confusing and irritating trigraph sequences were finally deprecated by this standard. An example for a trigraph sequence is ‘??<’, which denotes the opening curly bracket ({). The g++ compiler claims almost full support for the features required by the C++17 standard. It is recommended that you use g++ version 7 or higher to obtain this level of support. We can use the g++ option ‘-std=c++17’ to make sure that a program strictly conforms to the C++17 standard.

Now, consider the program pgm4.cc given below:

#include<iostream>
using namespace std;

int main()
{
	cout<<__cplusplus<<endl;
	return 0;
}

The compilation and execution steps of the program pgm4.cc when compiled as a C++17 program and a C++14 program are given below:

>> g++ -std=c++17 pgm4.cc
>> ./a.out
201703
>> g++ -std=c++14 pgm4.cc
>> ./a.out
201402

The output is different because the value of the macro _ _cplusplus is changed with every version. If you are working with different standards of C++, it is advisable that you print the value of this macro at the beginning of every program so as to make sure that you are working with the correct version.

C++20 standard
The latest standard of C++, informally called C++20 (official document ISO/IEC 14882:2020), was introduced in 2020. Deviating from tradition, whereby the release of a major standard is followed by the release of a minor standard, C++20 has brought in some major changes to C++. It is widely believed that C++20, like C++98 and C++11 before, will change the way C++ is perceived by programmers. C++20 has 81 keywords. Eight more keywords were added to the existing 73 keywords of C++17. They are char8_t, concept, consteval, constinit, co_await, co_return, co_yield and requires. As mentioned earlier, we are not counting the 11 alternative representations for operators and punctuators as keywords. So remember, suppose if someone tells you that there are 92 keywords in C++20, you should not contest the claim.

The previously unused and reserved keyword export is again used with C++20. But this time, this keyword is used to mark a declaration, a group of declarations, or another module exported by the current module. But the status of the previously unused and reserved keyword register remains the same in C++20 also. Special types of functions called coroutines that can have their execution suspended and resumed are implemented in C++20. The keywords co_await, co_return and co_yield are used to manipulate coroutines. A mechanism called modules that will help us divide large amount of code into logical sections was also introduced in C++20.

Being very recent, C++20 is not yet fully supported by compilers. The support for C++20 has started with g++ compiler version 8. Since this support is an ongoing process, it is better to use g++ compiler version 11 (the latest version as of April 2021). Since my preferred version is C++11, I never had to update version 7 of g++ in my system. The command ‘g++ –version’ will tell you the version of the g++ compiler in your system. If the version is older than version 8, then you won’t be able to use the g++ option ‘-std=c++20’. But there is an easy way to overcome this problem. Since g++ is a part of the Ubuntu tool chain, you can install g++ version 11 in your system with the command ‘sudo apt install g++-11’. The default version of g++ will still be your older version. Make sure that you use the command ‘g++-11’ instead of ‘g++’ when you need to use version 11, because the command ‘g++’ will only invoke the older version of g++. Now, consider the program pgm5.cc given below:

#include<iostream>
using namespace std;

consteval int cube(int x)
{
return x*x*x;
}

int main()
{
constexpr int n = cube(5);
cout<<n<<endl;
return 0;
}

The keyword consteval declares a function as an immediate function. An immediate function returns a constant value at compile time. This is especially useful for optimisation purposes. The compilation and execution of the program pgm5.cc conforming to the C++20 standard is given below:

>> g++-11 -std=c++20 pgm5.cc
>> ./a.out
125

C++23 standard
C++23 is the upcoming standard of C++. Some of the proposed features of C++23 include usage of a literal suffix for signed size_t, modified syntax for lambda functions, Standard Library support for coroutines, the creation of a modular Standard Library, etc. Experimental support for some of these proposed features of C++23 is already available in g++, including usage of a literal suffix for signed size_t, modified syntax for lambda functions, etc. The experimental support for C++23 only began with g++ version 11. Thus, we need g++-11 to use the option ‘=std=c++23’. Since we have already installed g++-11 in our system, we can directly use it. The compilation and execution of the program pgm5.cc conforming to the C++23 standard is given below:

>> g++-11 -std=c++23 pgm5.cc
>> ./a.out
125

Now it is time to end our discussion. I do agree that our treatment of different C++ standards was very limited. Moreover, some of the features added in the latest C++ standards are a bit tricky to understand. But the aim of the article is only to discuss the different standards themselves. Also, now we know which specific version of g++ may be used to compile programs conforming to a particular standard. Though the official ISO standardisation documents of C++ are not free (as in free beer), working drafts are freely available on the Internet. With the help of those documents, interested programmers can dig deeper into a particular C++ standard for which they have a liking.

But before we part ways, one question needs to be answered. What standard of C++ should a young student adopt? The choices include the most popular (C++98, at least in academia), the most stable and modern (C++17), and the most modern (C++20). Though it is a matter of personal choice, I would suggest the adoption of C++17 or C++11 over C++98. It is a fact that the changes brought in by C++20 are more profound when compared with C++17. But adoption of C++20, while awaiting full support from compilers, might be a bit risky at this stage. If you are familiar with C++ and planning to adopt C++11, I suggest the textbook ‘The C++ Programming Language (4th Edition)’. If you are familiar with C++ and planning to adopt C++17, I suggest the text book ‘A Tour of C++ (2nd Edition)’. Both the textbooks are written by Bjarne Stroustrup. Yes! Why learn from a disciple when you can learn from the master himself.

LEAVE A REPLY

Please enter your comment!
Please enter your name here