Chapter 2. Variables and Basic Types
2.1 Primitive Built-in Types
C++ defines a set of primitive types that include the arithmetic types and a special type named void. The arithmetic types represent characters, integers, boolean value, and floating-point number. The void type has no associated values and can be used in only a few circumstances, most commonly as the return type for functions that do not return a value.
2.1.1 Arithmetic Types
The arithmetic types and divided into two categories: integral type (which include character and boolean types) and floating-point types.
The smallest chunk of addressable memory is referred to as a byte. The basic unit of storage, usually a small number of bytes, is referred to as a word.
Except for bool and the extended character types, the integral types may be signed or unsigned. A signed type represents negative of positive numbers (including zero); an unsigned type represents only values greater than or equal to zero.
There are three distinct basic character types char, signed char, and unsigned char, but there are only two representations: signed and unsigned. The char type uses one of these representations. Which of the other two character representations is equivalent to char depends on the compiler.
2.1.2 Type Conversions
The type of an object defines the data that an object might contain and what operations that object can perform. Among the operations that many types support is the ability to convert objects of the given type to other, related types.
Programs that contain undefined behaviour can appear to execute correctly in some circumstances and/or some compilers. There is no guarantee that the same program, compiled under a different compiler or even a subsequent release of the same compiler, will continue to run correctly.
As with any other out-of-range value, -1 will be transformed to an unsigned value.
2.1.3 Literals
literal is value self-evident.
Integer literals that begin with 0 are interpreted as octal. Those that begin with either 0x or oX are interpreted as hexadecimal.
Although integer literals may be stored in signed types, technically speaking, the value of a decimal literal is never a negative number, the minus sign is not part of the literals.
Floating-point literals include either a decimal point or an exponent specified using scientific notation.
A character enclosed within single quotes is a char literal. Zero or more characters enclosed in double quotation marks is a string literal:
Some characters are non-printable, the escape sequence to represent such characters. An escape sequence begins with a backslash.
new line
\n
horizontal table
\t
alert(bell)
\a
vertical tab
\v
backspace
\b
double quote
\"
backslash
\\
question mark
\?
single quote
\'
carriage return
\r
formfeed
\f
The default type of an integer, floating-point, or character literal can be override by supplying a suffix or prefix.
Prefix
Suffix
u
char16_t (Unicode 16 character)
u or U
unsigned
U
char32_t (Unicode 32 character)
l or L
long
L
wchar_t (wide character)
ll or LL
long long
u8
char (utf-8)
f or F
float
l or L (for floating-point number)
long double
The words true and false are literals of type bool.
2.2 Variables
A variable provides the named storage that programs can manipulate.
2.2.1 Variable Definitions
A simple variable definition consists of a type specifier, followed by a list of one or more variable names separated by commas, and ends with a semicolon.
An object that is initialised gets the specified value at the moment it is created. Initialisation is not assignment. Initialisation happens when a variable is given a value when it is created. Assignment obliterates an objects's current value and replaces that value with a new one.
When we define a variable without an initialiser, the variable is default initialised. Such variables are given the "default" value. The value of an object of built-in type that is not explicitly initialised depends on where it is defined. Variables defined outside any function body are initialised to zero. With one exception, variables of built-in type defined inside a function are uninitialised.
2.2.2 Variable Declarations and Definitions
separate compilation lets user split the programs into several files, each of which can be compiled independently.
A declaration makes a name known to the program. A definition creates the associated entity. An extern that has an initialiser is a definition:
Variable must be defined exactly once but can be declared many times.
2.2.3 Identifiers
identifiers in C++ can be composed of letters, digits, and the underscore character. The language imposes no limit on name length. Identifiers must begin with either a letter or an underscore. Identifiers are case-sensitive; upper- and lowercase letters are distinct.
2.2.4 Scope of a Name
A scope is a part of the program in which a name has a particular meaning. For global scope, once declared, names at the global scope are accessible throughout the program. For block scope, it is only accessible in the body of function or block which defines the variable.
Once a name has been declared in a scope, that name can be used by scopes nested inside that scope. Names declared in the outer scope can also be redefined in an inner scope:
2.3 Compound Types
A compound type is a type that is defined in terms of another type. C++ has several compound types, two of which -- references and pointers.
2.3.1 References
A reference defines an alternative name for an object, the compiler only binds the reference to its initialiser instead of copying the initialiser's value.
A reference is not an object. Instead, a reference is just another name for an already existing object.
The type of a reference and the object to which the reference refers must match exactly.
2.3.2 Pointers
A pointer is a compound type that "points to" another type. Unlink a reference, a pointer is an object in its own right. Pointers can be assigned and copied; a single pointer can point to several different objects over its lifetime. Unlink a reference, a pointer need not be initialised at the time it is defined.
A pointer holds the address of another object. User can get the address of an object by using the address-of operator (the & operator); When a pointer points to an object, it can use the dereference operator (the * operator) to access that object.
A null pointer does not point to any object. There several ways to obtain a null point:
The most important is that a reference is not an object. Once a reference has been defined, there is no way to make that reference refer to a different object.
A pointer can be used in condition, if the pointer is 0, then the condition is false. The pointers can compare by the equality (==) or inequality (!=) operator.
The type void* is a special pointer type that can hold the address of any object.
For defining multiple variable of pointer:
The level of pointer can be indicated by its own *:
2.4 const Qualifier
The const can make a variable unchangeably. When a const object is initialised from a compile-time constant, the compiler will usually replace uses of the variable with its corresponding value during compilation.
Sometime we have a const variable that we want to share across multiple files but whose initialiser is not a constant expression. In this case, we don't want the compiler to generate a separate variable in each file. Instead, we want the const object to behave like other variables. We want to define the const in one file, and declare it in thee other files that use that object. To define a single instance of a const variable, we use the keyword extern on both its definition and declaration(s):
2.4.1 References to const
The reference to const is a reference that refers to a const type, it cannot be used to change the object to which the reference is bound:
2.4.2 Pointers and const
A pointer to const may not be used to change the object to which the pointer points, it must be initialised, and once initialised, its value may not be changed.
2.4.3 Top-Level const
The top-level const to indicate that the pointer itself is a const. A pointer to a const object refers to that const as a low-level const.
The distinction between top-level and low-level matters when we copy an object. When we copy an object, top-level const are ignored. On the other hand, low-level const is never ignored. When we copy an object, both objects must have the same low-level const qualification or there must be a conversion between the types of the two objects.
2.4.4 constexpr and Constant Expressions
A constant expression is an expression whose value cannot change and that can be evaluated at compile time. We can ask the compiler to verify that a variable is a constant expression by declaring the variable in a constexpr declaration.
Because a constant expression is one that can be evaluated at compile time, there are limits on the types that we can use in a constexpr declaration. The types we can use in a constexpr are known as "literal types" because they are simple enough to have literal values.
A pointer in a constexpr declaration, the constexpr specifier applies to the pointer, not the type to which the pointer point:
2.5 Dealing with Types
2.5.1 Type Aliases
A type alias is a name that is a synonym for another type. There are two ways to define a type alias, the first one is typedef:
The second ways is via an alias declaration:
2.5.2 The auto Type Specifier
The compiler can figure out the type by using the auto type specifier.
The type that the compiler infers for auto is not always exactly the same as the initialiser's type. Instead, the compiler adjusts the type to conform to normal initialisation rules.
2.5.3 The decltype Type Specifier
The decltype returns the type of its operand.
The compiler does not call f, but it uses the type that such a call would return as the type for sum.
The decltype of a parenthesised variable is always a reference:
2.6 Defining Our Own Data Structure
Our class begins with the keyword struct, followed by the name of the class and a class body.
The most common technique for making it safe to include a header multiple times relies on the preprocessor. The preprocessor, which C++ inherits from C, is a program that runs before the compiler and changes the source text of the programs.
C++ program also use the preprocessor to define header guards. The #define directive takes a name and defines that name as a preprocessor variable; #ifdef is true if the variable has been defined, and #ifndef is true is the variable has not been defined; If the test is true, then everything following the #ifdef or #ifndef is processed up to the matching #endif.
Last updated
Was this helpful?