[C++ Primer Reading Notes] Day 2

Scope

Chapter 2.1-2.2

Review

Chapter 2 mainly introduces the built-in types and the mechanisms for defining a class. Chapter 2.1 and 2.2 focus on built-in types and variables. The characters of built-in types are closely tied to their representation on the machine’s hardware. Once we find out how the computer hardware works, we can understand these complicated rules on using built-in types.

Notes

1. about arithmetic types

1.1 categories

The arithmetic types are decided into two categories: integral types (which include character and boolean types) and floating-point types.

It should be noticed that character and boolean types belong to integral types.

1.2 types in the memory

1.2.1 the size of the arithmetic types

The size of–that is, the number of bits–in arithmetic types varies accross machines.

Although the size different from machine to machine, there are still a few principles that every machine should follow:

A char is the same size as a single machine byte

The language garantees that an int will be at least as large as short, a long at least as large as int, and long long at least as large as long.

The size of the types is determined by the compiler. According to C90/C99 Note 2,

A byte is composed of a contiguous sequence of bits, the number of which is implementation defined.

Tha language provides a set of fundamental built-in types such as int and char, which are closely tied to their representation on the machine’s hardware.

Most compilers of 32-bit and 64-bit machine take 8 bits as a byte, which is also the size of a char, and take four bytes as the size of an int.

typeminimum sizecommon sizefeature
boolNA1 byte
char1 byte1 byte
wchar_t2 bytes
char16_t2 bytesUnicode
char32_t4 bytesUnicode
short2 bytes
int2 bytes4 bytes
long4 bytes4 bytes
long long8 bytes8 bytes
float4 bytes6 significant digits
double8 bytes10 significant digits
long double12 or 16 bytes10 significant digits
1.2.2 the address of a byte in the memory

Most computers associate a number (called an “address”) with each byte in memory.

The addresses are given for each byte instead of each bit. It can be imagined that the computer takes a byte as the smallest unit that can be manipulated. We cannot define a variable that has the size smaller than a byte. We can name a byte but we cannot name a bit. There is not any operator that can operate a single bit. These are all because of the above statement.

Besides, it can be understood that the size of all kinds of type, including class type, must be a multiple of one byte.

To give meaning to memory at a given address, we must know the type of the value stored there. The type determins how many bits are used and how to interpret those bits.

That is to say when defining a variable with a specific type, the computer would assign enough memory (one or more bytes) to this variable according to the type classification at the same time.

1.3about the float-point types

1.3.1 the precision of the float-point types

The float and double types typically yield about 7 and 16 significant digits, respectively.

A float is represented by two numbers named m (mantissa) and e (exponent) as the following equation:
a = m × 2 e a=m\times2^e a=m×2e
The base number is always 2 in every computer binary representation. The range of m m m should be [ 1.0 , 2.0 ] [1.0, 2.0] [1.0,2.0]. 32 bits, which amount to 4 bytes, is used to represent a float. The highest bit is the sign bit. The 8 bits in the middle are used to represent e e e. The lowest 23 bits are used to represent &m&. The largest number 23 bits can represent is 2 23 − 1 = 8388607 2^{23}-1=8388607 2231=8388607. Therefore, a float type can have 7 significant digits at most. Because not all 7 significant digits number can be represented by float, we should say that a float type can yield 6 significant digits. It is the same for the double type. The 11 bits in the middle are used to represent e e e. The lowest 52 bits are used to represent &m&. The largest number 52 bits can represent is 2 52 − 1 2^{52}-1 2521.

1.3.2 the differences amounts three float-point types

Use double for float-point computations; float usually does not have enough precision, and the cost of double-precision calculations versus single-precision is negligible. In fact, on some machines, double-precision operations are faster than single. The precision offered by long double usually is unnecessary and often entails considerable run-time cost.

This is because, for both float and double, their operators deal with numbers using double-precision. The computer has to transfer a float to a double before it performs its operation, which takes some extra time.

1.4about the integral types

1.4.1 the signed and unsigned type of integral types

Except for bool and the extended character types, the integral types may be signed or unsigned.

For int types, it is very simple to distinguish signed and unsigned.

typesfeature
int, short, long, long longsigned
unsigned, unsigned short, unsigned long, unsigned long longunsigned

For char types, to distinguish the two types is not so straight forward.

Although there are three character types, there are only two representations: signed and unsigned. The (plain) char type uses one of these representation. Which of the two character representations is equivalent to char depends on the compiler.

typesfeature
charsigned or unsigned
signed charsigned
unsigned charunsigned

Caution:

Do not use plain char or bool in arithmetic expressions. Computations using char are especially problematic because char is signed on some machines and unsigned on others. If you need a tiny integer, explicitly specify either signed char or unsigned char.

1.5 type conversions

Type conversions happen automatically when we use an object of one type where an object of another type is expected.

fromtoresult
nonbool arithmetic typesboolfalse, if the value is 0; true, if the value is not 0
boolnonbool arithmetic types1, if the value is true; 0, if the value is false
float-pointintegraltruncated
integralfloat-pointthe fractional part is zero; precision may be lost if the integral has more bits than the float-point object can accommodate
out-of-range valueunsigned typethe remainder of the value modulo the number of values the target type can hold, eg: -1 -> 255
out-of-range valuesigned typeundefined

We should be careful to make sure the automatic type conversion is what we expect. Avoid assigning an out-of-range value to a signed or unsigned type.

Caution:

If we use both unsigned and int values in an arithmetic expression, the int value ordinarily is converted to unsigned.

It is essential to remember that signed values are automatically converted to unsigned.

When the computer converts a negative value to an object of unsigned type, which can be seen as the situation that an out-of-range value is converted to an unsigned type, the machine code in the memory does not change. For example,

undigned char u = 10;
signed char i = -42;
std::cout << i + i << std::endl;
std::cout << i + u << std::endl;

In the second cout statement, i would be converted to an unsigned char before the calculation begins. The machine code of i of signed char type is 11010110 11010110 11010110, where the the highest bit is a sign bit. Now that this machine code should be treated as an unsigned char, the highest bit is not a sign bit any more. Therefore, it is 86 in unsigned char type. This result is exactly the same to what we can get if we calculate like this: − 42 % 2 8 = 86 -42\%2^8=86 42%28=86, which is the remainder of the value modulo the number of values the target type can hold as we mention above.

1.6 unsigned types in a loop

That fact that an unsigned cannot be less than zero also affects how we write loops.

For example, here is the correct statement.

for (int i = 10; i >= 0; --1)
	std::cout << i << std::endl;

If we use unsigned instead of int, the loop will never end because an unsigned number can never be less than 0. That is to say, the ending condition can never be satisfied.

for (unsigned i = 10; i >= 0; --1)
	std::cout << i << std::endl;

1.7 about the literals

1.7.1 integer literals

We can write an integer literal using octal, decimal, or hexadecimal notation.

begin withinteger formexample
0octal024
decimal20
0x, 0Xhexadecimal0x14

By default, decimal literals are signed whereas octal and hexadecimal literals can be either signed or unsigned types.

Besides, we can specify the type of a literal using a prefix or suffix.
For integer literals,

prefix or suffixtype
-u, -Uunsiged
- l, -Llong
-ll, -LLlong long

Caution:

When you write a long literal, use the uppercase L; the lowercase letter l is too easily mistaken for the digit 1.

1.7.2 float-point literals

For float-point literals,

prefix or suffixtype
-f, -Ffloat
-l, -Llong
1.7.3 char or string literals

For char or string literals,

prefix or suffixtype
u-char16_t
U-char32_t
L-wchar_t
u8-char (utf-8, string literals only)

Some characters, such as backspace or control characters, have no visible image. Such characters are nonprintable. Other characters (single and double quotation marks, question mark, and backslash) have special meaning in the language. Our programs cannot use any of these characters directly. Instead, we use an escape sequence to represent such characters.

characterescape sequence
new line\n
horizontal tab\t
vertical tab\v
backspace\b
double quote\"
single quote\’
backslash\
question mark\?
carriage return\r
character in hexadecimal form\x followed by one or more hexadecimal digits
charaacter in octal form\ followed by at most three octal digits

2. about variables

2.1 initialization

2.1.1 several forms of initialization:
int units_sold = 0;
int units_sold = {0};  // list initialization
int units_sold{0};  // list initialization
int units_sold(0);

List initialization is a new feature of C++11.

2.1.2 the difference between initialization and assignment

Initialization and assignment are different operations in C++

When we use list initialization,

the compiler will not let us list initialize variables of built-in type if the initializer might lead to the loss of information.

That is to say, when we use list initialization, there will be no automatic conversion of types and thus cause an error. It works in a different way from assignment.

2.1.3 default initialization

Variables defined outside any function body are initialized to zero.

Variables of built-in type defined inside a function are uninitialized, The value of an uninitialized variable of built-in type is undefined. It is an error to copy or otherwise try to access the value of a variable whose value is undefined.

2.2 declarations and definitions

A declaration makes a name known to the program.
the variable with an initial value.
A variable declaration specifies the type and name of a variable.
More generally, a declaration is a base type followed by a list of declarators. Each declarators names a variable and give the variable a type that is related to the base type.

A definition creates the associated entity.
In addition to specifying the name and type, a definition also allocates storage and may provide the variable with an initial value.

A variable definition is a declaration.

S d e f S_{def} Sdef is the set of all variable definitions
S d e c S_{dec} Sdec is the set of all variable declarations
S d e f ⊂ S d e c S_{def} \subset S_{dec} SdefSdec

To obtain a declaration that is not also a definition, we add the extern keyword and may not provide an explicit initializer.

If we want a declaration x x x that x ∈ S d e c x \in S_{dec} xSdec and x ∉ S d e f x \notin S_{def} x/Sdef, we should add extern, and not to initialize.

2.3 scope

The global scope has no name. Hence, when the scope operator has an empty left-hand side, it is a request to fetch the name on the right-hand side from the global scope.

Word List

integral types 整形
literals 字面值
octal 八进制
hexadecimal 十六进制
escape sequence 转义字符
identifier 标识符

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值