© Ray Lischner 2020
R. LischnerExploring C++20https://doi.org/10.1007/978-1-4842-5961-0_2

2. Reading C++ Code

Ray Lischner1 
(1)
Ellicott City, MD, USA
 
I suspect you already have some knowledge of C++. Maybe you already know C, Java, Perl, or other C-like languages. Maybe you know so many languages that you can readily identify common elements. Let’s test my hypothesis. Take a few minutes to read Listing 2-1, then answer the questions that follow it.
 1 /// Read the program and determine what the program does.
 2
 3 import <iostream>;
 4 import <limits>;
 5
 6 int main()
 7 {
 8     int min{std::numeric_limits<int>::max()};
 9     int max{std::numeric_limits<int>::min()};
10     bool any{false};
11     int x;
12     while (std::cin >> x)
13     {
14         any = true;
15         if (x < min)
16             min = x;
17         if (x > max)
18             max = x;
19     }
20
21     if (any)
22         std::cout << "min = " << min << " max = " << max << ' ';
23 }
Listing 2-1.

Reading Test

What does Listing 2-1 do?
  • _____________________________________________________________

  • _____________________________________________________________

  • _____________________________________________________________

  • _____________________________________________________________

Listing 2-1 reads integers from the standard input and keeps track of the largest and smallest values entered. After exhausting the input, it then prints those values. If the input contains no numbers, the program prints nothing.

Let’s take a closer look at the various parts of the program.

Comments

Line 1 begins with three consecutive slashes to start a comment. The comment ends at the end of the line. Actually, you need only two slashes to signal the start of a comment (//), but as you will learn later in the book, the extra slash has a special meaning.

Note that you cannot put a space between the slashes. That’s true in general for all the multicharacter symbols in C++. It’s an important rule and one you must internalize early. A corollary to the “no spaces in a symbol” rule is that when C++ sees adjacent characters, it usually constructs the longest possible symbol, even if you can see that doing so would produce meaningless results.

The other method you can use to write a comment in C++ is to begin the comment with /* and end it with */. The difference between this style and the style demonstrated in Listing 2-1 is, with this method, your comment can span multiple lines. You may notice that some programs in this book use /** to start a comment. Much like the third slash in Listing 2-1, this second asterisk (*) is magic, but unimportant at this time. A comment cannot nest within a comment of the same style, but you can nest one style of comment in comments of the other style, as illustrated in Listing 2-2.
/* Start of a comment /* start of comment characters are not special in a comment
 // still in a comment
 Still in a comment
*/
no_longer_in_a_comment();
// Start of a comment /* start of comment characters are not special in a comment
no_longer_in_a_comment();
Listing 2-2.

Demonstrating Comment Styles and Nesting

The C++ community uses both styles widely. Get used to seeing and using both styles.

Modify Listing 2-1 to change the /// comment to use the /** ... */ style, then try to recompile the program. What happens?
  • _____________________________________________________________

If you made the change correctly, the program should still compile and run normally. The compiler eliminates comments entirely, so nothing about the final program should be different. (With one exception being that some binary formats include a timestamp, which would necessarily differ from one compilation run to another.)

Modules

Lines 3 and 4 of Listing 2-1 import declarations and definitions from parts of the standard library. C++, like C and many other languages, distinguishes between the core language and the standard library. Both are part of the standard language, and a tool suite is incomplete without both parts. The difference is that the core language is self-contained. For example, certain types are built-in, and the compiler inherently knows about them. Other types are defined in terms of the built-in types, so they are declared in the standard library, and you must instruct the compiler that you want to use them. That’s what lines 3 and 4 are all about.

IMPORTING VS. INCLUDING

As I write this, no compiler (even the latest prerelease) can compile Listing 2-1 because of its import declarations. Understanding what import does and how it works is sufficiently complicated that I don’t cover it until Exploration 2. But here it is, interfering in Exploration 42.

Any time you see an import declaration, you can change it to an #include directive. Just substitute #include for import and delete the semicolon at the end of the line. The code listings on the book’s website (https://cpphelp.com/exploring/) provide both styles of files. Download the files that work for your development environment without concerning yourself with what import or #include actually means.

Implementing the import keyword is only one part of a much larger task, so it will take some time for the compilers and libraries to catch up. Until then, we have a workaround.

In particular, line 3 informs the compiler about the names of the standard I/O streams (std::cin for the standard input and std::cout for the standard output), the input operator (>>), and the output operator (<<). Line 4 brings in the name std::numeric_limits. Note that names from the standard library generally begin with std:: (short for “standard”).

In C++ parlance, the import keyword is also a verb, as in “line 3 imports the iostream module,” “line 4 imports the limits module,” and so on. A module contains a series of declarations and definitions. (A declaration is a kind of definition. A definition tells the compiler more about a name than a declaration. Don’t worry about the difference yet, but notice when I use declaration and when I use definition.) The compiler needs these declarations and definitions, so it knows what to do with names such as std::cin. Somewhere in the documentation for your C++ compiler and standard library is information about its standard modules. If you are curious, you can probably visit a folder or directory that contains the source code for the standard modules and see what you can find there, but don’t be disappointed if you can’t understand them. The C++ standard library makes full use of the entire range of C++ language features. It’s likely you won’t be able to decipher most of the library until after you’ve made it through a large part of this book.

Another important C++ rule: the compiler has to know what every name means. A human can often infer meaning or at least a part of speech from context. For example, if I were to say, “I furbled my drink all over my shirt,” you may not know exactly what furbled means, but you can deduce that it is the past tense of a verb and that it probably implies something undesirable and somewhat messy.

C++ compilers are a lot dumber than you. When the compiler reads a symbol or identifier, it must know exactly what the symbol or identifier means and what part of “speech” it is. Is the symbol a punctuator (such as the statement-ending semicolon) or an operator (such as a plus sign for addition)? Is the identifier a type? A function? A variable? The compiler also has to know everything you can do with that symbol or name, so it can correctly compile the code. The only way it can know is for you to tell it, and the way you tell it is by writing a declaration or by importing a declaration from a module. And that’s what import declarations are all about.

Later in the book, you’ll even learn to write your own modules.

Modify line 4 to misspell limits as stimil. Try to compile the program. What happens?
  • _____________________________________________________________

  • _____________________________________________________________

  • _____________________________________________________________

The compiler cannot find any module named stimil, so it issues a message. Then it may try to compile the program, but it doesn’t know what std::numeric_limits is, so it issues one or more messages. Some compilers cascade messages, which means every use of std::numeric_limits produces additional messages. The actual error becomes lost in the noise. Focus on the first one or few messages the compiler issues. Fix them, then try again. As you gain experience with C++, you will learn which messages are mere noise and which are important. Unfortunately, most compilers will not tell you, for example, that you can’t use std::numeric_limits until you include the <limits> module. Instead, you need a good C++ language reference, so you can look up the correct header on your own. The first place to check is the documentation that accompanies your compiler and library. Authors have been slower than compiler writers to catch up to the C++ 20 standard, so keep checking the website and bookstores for updated references.

Most programmers don’t use <limits> much; Listing 2-1 included it only to obtain the definition of std::numeric_limits. On the other hand, almost every program in this book uses <iostream>, because it declares the names and types of the I/O stream objects, std::cin and std::cout. There are other I/O modules, but for basic console interactions, you need only <iostream>. You will meet more modules in coming Explorations.

Main Program

Every C++ program must have int main(), as shown on line 6. You are permitted a few variations on a theme, but the name main is crucial. A program can have only one main, and the name must be spelled using all lowercase characters. The definition must start with int.

Note

A few books instruct you to use void. Those books are wrong. If you have to convince someone that void is wrong and int is right, refer the skeptic to section [basic.start.main] of the C++ standard.

For now, use empty parentheses after the name main.

The next line starts the main program. Notice how the statements are grouped inside curly braces ({ and }). That’s how C++ groups statements. A common error of novices is to omit a curly brace or miss seeing them when reading a program. If you are used to more verbose languages, such as Pascal, Ada, or Visual Basic, you might need some time acquainting yourself with the more terse C++ syntax. This book will give you plenty of opportunities to practice.

Modify line 6 to spell main in capital letters (MAIN). Try to compile the program. What happens?
  • _____________________________________________________________

  • _____________________________________________________________

  • _____________________________________________________________

The compiler probably accepts the program, but the linker complains. Whether you can see the difference between the compiler and the linker depends on your particular tools. Nonetheless, you failed to create a valid program, because you must have a main. Only the name main is special. As far as the compiler is concerned, MAIN is just another name, like min or max. Thus, you don’t get an error message saying that you misspelled main, only that main is missing. There’s nothing wrong with having a program that has a function named MAIN, but to be a complete program, you must be sure to include the definition main .

Variable Definitions

Lines 8 through 11 define some variables. The first word on each line is the variable’s type. The next word is the variable name. The name is followed optionally by an initial value in curly braces. The type int is short for integer, and bool is short for Boolean.

Note

Boolean is named after George Boole, the inventor of mathematical logic. As such, some languages use the name logical for this type. It is unclear why languages such as C++ use bool instead of boole for the type named after Boole.

The name std::numeric_limits is part of the C++ standard library and lets you query the attributes of the built-in arithmetic types. You can determine the number of bits a type requires, the number of decimal digits, the minimum and maximum values, and more. Put the type that you are curious about in angle brackets. (You’ll see this approach to using types quite often in C++.) Thus, you could also query std::numeric_limits<bool>::min() and get false as the result.

If you were to query the number of bits in bool, what would you expect as a result? ________________

Try compiling and running Listing 2-3, and find out if you are correct.
import <iostream>;
import <limits>;
int main()
{
  // Note that "digits" means binary digits, i.e., bits.
  std::cout << "bits per bool: " << std::numeric_limits<bool>::digits << ' ';
}
Listing 2-3.

Determining the Number of Bits in a bool

Did you get the value you expected? If not, do you understand why you got 1 as a result?

Statements

Line 12 of Listing 2-1 contains a while statement . Lines 15, 17, and 21 begin if statements. They have similar syntax: both statements begin with a keyword, followed by a Boolean condition in parentheses, followed by a statement. The statement can be a simple statement, such as the assignment on line 16, or it can be a list of statements within curly braces. Notice that a simple statement ends with a semicolon.

Assignment (lines 14, 16, and 18) uses a single equal sign. For clarity, when I read a program out loud or to myself, I like to read the equal sign as “gets.” For example, “x gets min.”

A while loop performs its associated statement while the condition is true. The condition is tested prior to executing the statement, so if the condition is false the first time around, the statement never executes.

On line 12, the condition is an input operation. It reads an integer from the standard input (std::cin) and stores that integer in the variable x. The condition is true as long as a value is successfully stored in x. If the input is malformed, or if the program reaches the end of the input stream, the logical condition becomes false, and the loop terminates.

The if statement can be followed by an else branch; you’ll see examples in future Explorations.

Line 21’s condition consists of a single name: any. Because it has type bool, you can use it directly as a condition.

Modify line 15 to change the statement to just “if (x)”. This kind of mistake sometimes occurs when you get careless (and we all get careless from time to time). What do you expect to happen when you compile the program?
  • _____________________________________________________________

  • _____________________________________________________________

Were you surprised that the compiler did not complain? What do you expect to happen when you run the program?
  • _____________________________________________________________

  • _____________________________________________________________

  • _____________________________________________________________

If you supply the following input to the program, what do you expect as output?
0   1   2   3
  • _____________________________________________________________

  • _____________________________________________________________

If you supply the following input to the program, what do you expect as output?
3   2   1   0
  • _____________________________________________________________

  • _____________________________________________________________

Explain what is happening.
  • _____________________________________________________________

  • _____________________________________________________________

  • _____________________________________________________________

  • _____________________________________________________________

  • _____________________________________________________________

C++ is permissive about what it allows as a condition. Any numerical type can be a condition, and the compiler treats nonzero values as true and zero as false. In other words, it supplies an implicit ≠ 0 to test the numeric value.

Many C and C++ programmers take advantage of the brevity these languages offer, but I find it a sloppy programming practice. Always make sure your conditions are logical in nature, even if that means using an explicit comparison to zero. The C++ syntax for comparing ≠ is !=, as in x != 0.

Output

The output operator is <<, which your program gets by importing <iostream>. You can print a variable’s value, a character string, a single character, or a computed expression.

Enclose a single character in single quotes, such as 'X'. Of course, there may be times when you have to include a single quote in your output. To print a single quote, you will have to escape the quote character with a backslash ('). Escaping a character instructs the compiler to process it as a standard character, not as a part of the program syntax. Other escape characters can follow a backslash, such as for a newline (i.e., a magic character sequence to start a new line of text; the actual characters in the output depend on the host operating system). To print a backslash character, escape it: ''. Some examples of characters include these: 'x', '#', '7', '', ' '.

If you want to print more than one character at a time, use a character string, which is enclosed in double quotes. To include a double quote in a string, use a backslash escape:
std::cout << "not quoted; "in quotes", not quoted";

A single output statement can use multiple occurrences of <<, as shown in line 22, or you can use multiple output statements. The only difference is readability.

Modify Listing 2-3 to experiment with different styles of output. Try using multiple output statements.

Remember to use curly braces when the body of an if statement contains more than one statement.

See! I told you that you could read a C++ program. Now all you have to do is fill in some of your knowledge gaps about the details. The next Exploration starts doing that with the basic arithmetic operators.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.126.11