Week 7
In this lecture we will briefly look at function inlining, then talk about C++ constants and introduce formatted output when using C++ streams (as opposed to C's printf).
Inlining functions
By function inlining we mean that the function's code gets inserted into the caller's code by expanding the function call to the function definition (conceptually similar to what happens with a #define macro). This can, depending on many things, improve performance, because the compiler can perform more optimizations on this straight-line code than it typically can on code that contains function calls.
There are several ways to designate that a function is inlinable, some of which involve the inline
keyword, others do not. No matter how you designate a function as inlinable, it is a just a request that the compiler is allowed to ignore: it might expand some, all, or none of the calls to an inlined function.
Why not always inline? When you inline functions, you are increasing the number of instructions in your program, which consumes memory and also can lead to bad performance if, for example, you have a very large loop body, whose instructions do not fit in the instruction cache.
Example:
- // A.hpp
- class A {
- public:
- void foo(int i, char c);
- };
Then in the A.cpp
file:
- inline
- void A::foo(int i, char c)
- {
- ...
- }
You can also include the function definition in the header file, although this is generally not a good programming practice.
- class A {
- public:
- void foo(int i, char c)
- {
- ...
- }
- };
Constants
Literals
Literals are obvious constants. They can be classified into integer, floating-point, characters, strings, booleans, pointers, and user-defined literals.
Integers:
- Decimals (base 10):1983, -251, 0
- Octal (base 8): 0116 (starts with 0)
- Hex (base 16): 0x4a, 0xca
The following are equivalent: 75 (decimal), 0113 (octal), 0x4b (hex)
All literals also have a type. By default, integer literals are of type int
. You can explicitly specify a different type by appending a suffix to the literal, for example
- unsigned:
13u
or13U
- long:
13l
or13l
- long long:
13ll
or13LL
Floating-point numbers
They express real values, with decimals and/or exponents. They can include either a decimal point, an e
character (scientific notation), or both a decimal point and an e
character:
- 3.14159 // 3.14159
- 6.02e23 // 6.02 x 1023
- 1.6e-19 // 1.6 x 10-19
- 3.0 // 3.0
The default type for floating-point values is double
. Floating-point literals of type float
or long double
can be specified by adding one of the following suffixes:
- f or F (float): 4.52F, 0.2f
- l or L (long double): 3.141592653589793238462643383279502884197169399375105820974L
Characters and strings
Similar to C, in C++ character literals are enclosed in single quotes ('a', 'b', 'X'), while strings are enclosed in double quotes ("hello", "kitten").
Character and string literals can also represent special characters that are difficult or impossible to express otherwise in the source code of a program, like newline (\n) or tab (\t). These special characters are all of them preceded by a backslash character (\).
Here you have a list of the single character escape codes:
Escape code | Description |
\n | newline |
\r | carriage return |
\t | tab |
\v | vertical tab |
\b | backspace |
\f | form feed (page feed) |
\a | alert (beep) |
\' | single quote (') |
\" | double quote (") |
\? | question mark (?) |
\\ | backslash (\) |
All the character literals and string literals described above are made of characters of type char. A different character type can be specified by using one of the following prefixes:
- u (char16_t): u'A', u'3'
- U (char32_t): U'b', U'/'
- L (wchar_t): L's'
Note that, unlike type suffixes for integer literals, these prefixes are case sensitive: lowercase for char16_t
and uppercase for char32_t
and wchar_t
.
For string literals, apart from the above u, U, and L, two additional prefixes exist:
- u8: The string literal is encoded in the executable using UTF-8
- R: The string literal is a raw string
In raw strings, backslashes and single and double quotes are all valid characters; the content of the literal is delimited by an initial R"sequence( and a final )sequence", where sequence is any sequence of characters (including an empty sequence). The content of the string is what lies inside the parenthesis, ignoring the delimiting sequence itself. For example:
R"&%$(string with \backslash)&%$"
Both strings above are equivalent to "string with \\backslash". The R prefix can be combined with any other prefixes, such as u, L or u8.
Other literals
Three keyword literals exist in C++: true
, false
and nullptr
:
true
and false
are the two possible values for variables of type bool
.
nullptr
is the null pointer value.
- bool foo = true;
- bool bar = false;
- int* p = nullptr;
Typed constant expressions
Sometimes, it is just convenient to give a name to a constant value:
- const double pi = 3.1415926;
- const char tab = '\t';
We can then use these names instead of the literals they were defined to:
- #include <iostream>
- using namespace std;
- const double pi = 3.14159;
- const char newline = '\n';
- int main ()
- {
- double r=5.0; // radius
- double circle;
- circle = 2 * pi * r;
- cout << circle;
- cout << newline;
- }
Constexpr
In C++11, you can also define constant expressions, that is, expressions that can be computed at compile time, for example:
Preprocessor definitions
We already talked about preprocessor macros (e.g., #define PI 3.1415
), but we mentioned them here again because they are one of the mechanisms for defining constants.
C++ output formatting
The std::setw
function allows you to set the minimum width of the next output via the insertion operator. setw
takes, one argument, the width of the next output (insertion), which is an integer. If the next output is too short, then spaces will be used for padding. There is no effect if the output is longer than the width -- the output won't be truncated. The only strange thing about setw
is that its return value must be inserted into the stream. The setw
function has no effect if it is called without reference to a stream (i.e., it does nothing noticeable). Here is a simple example:
cout<<setw(10)<<"first"<<"middle"<<"last";
The output from this looks like this:
first middlelast
You can also change the padding character to something other than a space. You do that by using the setfill
function, which takes a character to use for the padding. Note that setfill
should also be used as a stream manipulator only, so it must be inserted into the stream:
Printing Numbers
Another challenge in creating nice output is correctly formatting numbers as you have already done in C with printf
; for instance, when printing out a hexadecimal value, it would be nice if it were preceded by the "0x" prefix. More generally, it's nice to correctly set the number of trailing zeros after a decimal place.
Setting the precision of numerical output with setprecision
The setprecision
function can be used to set the maximum number of digits that are displayed for a number. Like setw
, it should be inserted into the stream. In fact, its usage is very similar to setw
in all respects. For instance, to print the number 2.71828 to 3 decimal places:
Note that setprecision
will change the precision until the next time it is passed into a given stream. So changing the above example to also print out 1.412 would result in the output of
2.71 1.41
More examples:
- double a = 3.1415926534;
- double b = 2006.0;
- double c = 1.0e-10;
- std::cout.precision(5);
- std::cout << "default:\n";
- std::cout << a << '\n' << b << '\n' << c << '\n';
- std::cout << '\n';
- std::cout << "fixed:\n" << std::fixed;
- std::cout << a << '\n' << b << '\n' << c << '\n';
- std::cout << '\n';
- std::cout << "scientific:\n" << std::scientific;
- std::cout << a << '\n' << b << '\n' << c << '\n';
Output in different bases
Sometimes numbers need to be printed in octal or hexadecimal. The setbase
function returns a value that can be passed into a stream to set the base of numbers to either base 8, 10, or 16. The input number is still read as a number in base ten, but it is printed in the given base. For instance,
will print out "20", which is 32 written in base 16. Note that you can use dec, oct, and hex as shorthand for setbase(10), setbase(8), and setbase(16) respectively when inserting into a stream. If you wish to include an indication of the base along with the printed number, you can use the setiosflags function, again passed into a stream, with an input of ios_base::showbase
. Using the ios_base::showbase
flag will append a "0x" in front of hexadecimal numbers and a 0 in front of octal numbers. Decimal numbers will be printed as normal.
This should get you started with the ability to create nicely formatted output in C++ without having to resort to returning to printf!