《Thinking in C++》读书笔记——Chapter 3: The C in C++ (2)

Chapter3: The C in C++ (2)


Bitwise operators


(1)The bitwise exclusive or, or xor (^)
produces a one in the output bit if one or the other input bit is a one, but not
both.

(2)Bitwise operators can be combined with the = sign to
unite the operation and assignment: &=, |=,
and ^= are all legitimate operations (since ~
is a unary operator it cannot be combined with the =
sign).

Casting Operators


In some situations it forces the compiler to treat data as if it were (for
instance) larger than it really is, so it will occupy more space in memory; this
can trample over other data. This usually occurs when casting pointers.

(1)static_cast

static_cast用法示例:


 1 //: C03:static_cast.cpp
2 void func(int) {}
3 int main() {
4 int i = 0x7fff; // Max pos value = 32767
5 long l;
6 float f;
7 // (1) Typical castless conversions:( to highlight these promotions.)
8 l = i;
9 f = i;
10 // Also works:
11 l = static_cast<long>(i);
12 f = static_cast<float>(i);
13 // (2) Narrowing conversions:( will often give you a warning)
14 i = l; // May lose digits
15 i = f; // May lose info
16 // Says "I know," eliminates warnings:
17 i = static_cast<int>(l);
18 i = static_cast<int>(f);
19 char c = static_cast<char>(i);
20 // (3) Forcing a conversion from void* :( Assigning from a void* is not allowed without a cast in C++)
21 void* vp = &i;
22 // Old way produces a dangerous conversion:
23 float* fp = (float*)vp;
24 // The new way is equally dangerous:
25 fp = static_cast<float*>(vp);
26 // (4) Implicit type conversions, normally
27 // performed by the compiler:( highlights the action)
28 double d = 0.0;
29 int x = d; // Automatic type conversion
30 x = static_cast<int>(d); // More explicit
31 func(d); // Automatic type conversion
32 func(static_cast<int>(d)); // More explicit
33 } ///:~

(2)const_cast

If you want to convert from a const to a
nonconst or from a volatile to a
nonvolatile, you use
const_cast.

 

(3)reinterpret_cast

This is the least safe of the casting mechanisms, and the one most likely to
produce bugs. A reinterpret_cast pretends that an object is
just a bit pattern that can be treated (for some dark purpose) as if it were an
entirely different type of object.

reinterpret_cast用法以及结果示例:


//: C03:reinterpret_cast.cpp
#include <iostream>
using namespace std;
const int sz = 100;
struct X { int a[sz]; };
void print(X* x) {
for(int i = 0; i < sz; i++)
cout << x->a[i] << ‘ ‘;
cout << endl << "--------------------" << endl;
}
int main() {
X x;
print(&x);
int* xp = reinterpret_cast<int*>(&x);
for(int* i = xp; i < xp + sz; i++)
*i = 0;
// Can‘t use xp as an X* at this point
// unless you cast it back:
print(reinterpret_cast<X*>(xp));
// In this example, you can also just use
// the original identifier:
print(&x);
} ///:~

结果如下:

(4)dynamic_cast

For type-safe downcasting. (以后介绍)

sizeof – an operator by itself


Note that sizeof is an operator, not a function. If you
apply it to a type, it must be used with the parenthesized form shown above, but
if you apply it to a variable you can use it without parentheses

Composite type creation


(1)Aliasing names with typedef


(2)Combining variables with struct


(3)Clarifying programs with enum


An enumerated data type is useful when you want to keep track of some sort of
feature:


 1 //: C03:Enum.cpp
2 // Keeping track of shapes
3 enum ShapeType {
4 circle,
5 square,
6 rectangle
7 }; // Must end with a semicolon like a struct
8 int main() {
9 ShapeType shape = circle;
10 // Activities here....
11 // Now do something based on what the shape is:
12 switch(shape) {//shape is really just an int in C
13 case circle: /* circle stuff */ break;
14 case square: /* square stuff */ break;
15 case rectangle: /* rectangle stuff */ break;
16 }
17 } ///:~
18

If you don’t like the way the compiler assigns values, you can do it
yourself, like this:

1 enum
ShapeType { 2 circle =
10, square = 20,
rectangle = 50 3
};

If you give values to some names and not to others, the compiler will use the
next integral value. For example,

1 enum snap { crackle = 25,
pop };

The compiler gives pop the value 26.

If you have an instance of an enumeration color called
a. In C you can say a++, but in C++ you
can’t.

(4)Saving memory with union


>>A union piles all the data into a single space; it
figures out the amount of space necessary for the largest item you’ve put in the
union, and makes that the size of the
union.

>>All the addresses of the union variables are the
same (in a class or struct, the addresses are different).

(5)Arrays


>>Arrays cannot be passed by value.

>>Just passing the address of an array isn’t enough information; you
must always be able to know how big the array is inside your function, so you
don’t run off the end of that array.

>>argv[0] is the path and name of the program
itself.

>>All you get from the command-line is character arrays; if you want to
treat an argument as some other type, you are responsible for converting it
inside your program.

>>The bits inside of floats and
doubles are divided into three regions: the exponent, the
mantissa, and the sign bit

>>You cannot add two pointers, and if you subtract pointers the result
is the number of elements between the two pointers. However, you can add or
subtract an integral value and a pointer.

The C assert( ) macro


When you use assert( ), you give it an argument that is an
expression you are “asserting to be true.” The preprocessor generates code that
will test the assertion. If the assertion isn’t true, the program will stop
after issuing an error message telling you what the assertion was and that it
failed.


1 //: C03:Assert.cpp
2 // Use of the assert() debugging macro
3 #include <cassert> // Contains the macro
4 using namespace std;
5 int main() {
6 int i = 100;
7 assert(i != 100); // Fails
8 } ///:~

结果如下:

When you are finished debugging, you can remove the code generated by the
macro by placing the line:

#define NDEBUG

in the program before the inclusion of <cassert>, or
by defining NDEBUG on the compiler command line. NDEBUG is a flag used in
<cassert>to change the way code is generated by the
macros.

Function addresses(函数指针,考点)


(1)To define a pointer to a function that has no arguments and
no return value, you say: void (*funcPtr)(); funcPtr is a pointer to a function
that takes no arguments and returns void. But void *funcPtr()declaring a
function (that returns a void*) rather than defining a variable.

(2)void * (*(*fp1)(int))[10]: fp1 is a pointer to a function
that takes an integer argument and returns a pointer to an array of 10 void
pointers.

(3)float (*(*fp2)(int,int,float))(int): fp2 is a pointer to a
function that takes three arguments (int, int, and float) and returns a pointer
to a function that takes an integer argument and returns a float.

(4)typedef double (*(*(*fp3)())[10])();fp3 a;: An fp3 is a
pointer to a function that takes no arguments and returns a pointer to an array
of 10 pointers to functions that take no arguments and return doubles.” Then it
says “a is one of these fp3 types.”

(5)int (*(*f4())[10])(): f4 is a function that returns a pointer
to an array of 10 pointers to functions that return integers.

(6)Using a function pointer:


 1 //: C03:PointerToFunction.cpp
2 // Defining and using a pointer to a function
3 #include <iostream>
4 using namespace std;
5 void func() {
6 cout << "func() called..." << endl;
7 }
8 int main() {
9 void (*fp)(); // Define a function pointer
10 fp = func; // Initialize it
11 (*fp)(); // Dereferencing calls the function
12 void (*fp2)() = func; // Define and initialize
13 (*fp2)();
14 } ///:~

(7)Arrays of pointers to functions:

This supports the concept of table-driven code; instead of using
conditionals or case statements, you select functions to execute based on a
state variable.

一个示例:


 1 //: C03:FunctionTable.cpp
2 // Using an array of pointers to functions
3 #include <iostream>
4 using namespace std;
5 // A macro to define dummy functions:
6 #define DF(N) void N() { 7 cout << "function " #N " called..." << endl; }
8 DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(g);
9 void (*func_table[])() = { a, b, c, d, e, f, g };
10 int main() {
11 while(1) {
12 cout << "press a key from ‘a‘ to ‘g‘ "
13 "or q to quit" << endl;
14 char c, cr;
15 cin.get(c); cin.get(cr); // second one for CR
16 if ( c == ‘q‘ )
17 break; // ... out of while(1)
18 if ( c < ‘a‘ || c > ‘g‘ )
19 continue;
20 (*func_table[c - ‘a‘])();
21 }
22 } ///:~
23

《Thinking in C++》读书笔记——Chapter 3: The C in C++ (2),码迷,mamicode.com

时间: 2024-10-20 09:38:20

《Thinking in C++》读书笔记——Chapter 3: The C in C++ (2)的相关文章

《程序员的数学思维修炼》 读书笔记 Chapter 1 数据的表示

1.未赋值的变量--初始化的必要性. 无初始化时,视语言的不同可能有以下几种情况 1)赋值0 2)赋值空 3)不改变该内存块原值,即随此刻值. 4)编译失败 2.除数为0的判断防ERROR 3.大整数的解决方法 1)在Pascal中超过数据类型上限是会报错的.C等则可能出奇葩数据.实质上更增加了挑错难度.(C类该特性待验证) 2)此时就需要我们所称的 高精度 计算--模拟算法. 通过String(AnsiString)或数组表示一个大整数 根据人类计算思维编写计算逻辑 加减乘代码(http://

读书笔记:Speech enhancement: theory and practice

选读<Speech enhancement: theory and practice>.主要是自己的读书笔记. Chapter 1:Introduction 第一章~第四章,主要介绍语音增强算法的基础知识; Chapter 2:Discrete-Time Signal Processing and Short-Time fourier Analysis Chapter 3:Speech Production and Perception Chapter 4:Noise Compensation

《深入理解计算机系统》 Chapter 7 读书笔记

<深入理解计算机系统>Chapter 7 读书笔记 链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(货被拷贝)到存储器并执行. 链接的时机 编译时,也就是在源代码被翻译成机器代码时 加载时,也就是在程序被加载器加载到存储器并执行时 运行时,由应用程序执行 链接器使分离编译称为可能. 一.编译器驱动程序 大部分编译系统提供编译驱动程序:代表用户在需要时调用语言预处理器.编译器.汇编器和链接器. 1.将示例程序从ASCⅡ码源文件翻译成可执行目标文件的步骤 (1)运

《Linux内核设计与实现》Chapter 2 读书笔记

<Linux内核设计与实现>Chapter 2 读书笔记 一.获取内核源码 1.使用Git 我们曾经在以前的学习中使用过Git方法 $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git 更新分支到Linux的最新分支 $ git pull 可以获取并随时保持与内核官方的代码树一致 2.安装内核源代码 压缩形式为bzip2 $ tar xvjf linux-x.y.z.tar.bz2 压缩

《Linux内核设计与实现》Chapter 5 读书笔记

<Linux内核设计与实现>Chapter 5 读书笔记 在现代操作系统中,内核提供了用户进程与内核进行交互的一组接口,这些接口的作用是: 使应用程序受限地访问硬件设备 提供创建新进程与已有进程进行通信的机制 提供申请操作系统其他资源的能力 一.与内核通信 1.系统调用的作用 系统调用在用户空间进程和硬件设备之间添加了一个中间层,作用是: 为用户空间提供了一种硬件抽象接口: 系统调用保证了系统的稳定和安全,即可以避免应用程序不正确地使用硬件设备,窃取其他进程的资源: 每个进程都运行在虚拟系统中

《Linux内核设计与实现》Chapter 3 读书笔记

<Linux内核设计与实现>Chapter 3 读书笔记 进程管理是所有操作系统的心脏所在. 一.进程 1.进程就是处于执行期的程序以及它所包含的资源的总称. 2.线程是在进程中活动的对象. 3.进程提供两种虚拟机制:虚拟处理器和虚拟内存. 4.内核调度的对象是线程,而不是进程. 二.进程描述符及任务结构 内核把进程的列表存放在叫做任务队列的双向循环链表中.链表中的每一项都是类型为task_struct的进程描述符结构,该结构定义在<linux/sched.h>文件中. 1.分配进

SQL Server2012 T-SQL基础教程--读书笔记(5-7章)

SQL Server2012 T-SQL基础教程--读书笔记(5-7章) SqlServer T-SQL 示例数据库:点我 Chapter 05 表表达式 5.1 派生表 5.1.1 分配列别名 5.1.2 使用参数 5.1.3 嵌套 5.1.4 多个引用 5.2 公用表表达式 5.2.1 分别列别名 5.2.2 使用参数 5.2.3 定义多个CTE 5.2.4 CTE的多次引用 5.2.5 递归CTE 5.3 视图 5.3.1 视图和ORDER BY 子句 5.3.2 视图选项 5.4 内嵌表

SQL Server2012 T-SQL基础教程--读书笔记(8 - 10章)

SQL Server2012 T-SQL基础教程--读书笔记(8 - 10章) 示例数据库:点我 CHAPTER 08 数据修改 8.1 插入数据 8.1.1 INSERT VALUES 语句 8.1.2 INSERT SELECT 语句 8.1.3 INSERT EXEC 语句 8.1.4 SELECT INTO 语句 8.1.5 BULK INSERT 语句 8.1.6 标识列属性和序列对象 8.1.6.1 标识列属性 8.1.6.2 序列对象 8.2 删除数据 8.2.1 DELETE 语

SQL Server2012 T-SQL基础教程--读书笔记

SQL Server2012 T-SQL基础教程--读书笔记 SqlServer Chapter 01 T-SQL 查询和编程背景 1.3 创建表和定义数据的完整性 1.3.1 创建表 1.3.2 定义数据的完整性 1. 主键约束 2. 唯一约束 3. 外键束约 4. CHECK约束 5. 默认约束 Chapter 02 单表查询 2.1 SELECT 语句元素 2.1.7 TOP和OFFSET-FETCH 1. TOP筛选 2. OFFSET-FETCH 2.1.8 开窗函数速览 2.2 谓词