自从使用Quick-cocos-lua之后,已经很久没有大量写c++代码,介于要接受一个服务器项目,先回顾一下之前的只是。顺道把之前看C++ Primer的一些笔记整理一下。
字节
bit 一个二进制位 0
byte 一个字节 8个2进制位 01010101
char 1位 ff
int 4位 ff ff ff ff
float double
float为单精度,内存中占4个字节 32bit 有效位为7位,因为有符号
double为双精度,内存中占8个字节 64bit 有效位为16位
小数默认是double
无论是单精度还是双精度在存储中分为3个部分
1符号位 0代表正 1代表负
2指数位 用于存储科学计数法中得指数数据,并且采用移位存储
3尾数部分
符号位 指数位 尾数
float 1 8 23
double 1 11 52
8.25用二进制表示为 1000.01
任何一个数用二进制都表示1.XXXXX
第一位都是1,所以省略,
所以23bit的尾数部分,可以表示变成了24bit
9用二进制表示为1001
所以4bit能精确十进制中得1位小数点
24bit能精确到小数点后6位
120.5
1.1101101*2^6
0 127+6=133 1101101
0 10000101 11011010000000000000000
头文件
C语言编译器会用一些目录存放公共头文件、
* <>则只在这些目录下找头文件
* “”先在当前目录下找,如果找不到则在这些目录下找。
不可能搜索所有目录,这样效率太低。
一般来说,自己定义的头文件应该用”“,因为这些文件放在工程目录(也就是编译器的当前目录)下,而不是放在公共头文件目录下,如果用<>则找不到头文件。
而系统提供的头文件,比如库函数的头文件,可以用<>
申明和定义
只有申明也是定义时,申明才可以有初始化,因为只有定义才分配存储空间。
//申明变量而不定义它
extern int i
//声明并定义它
const
const 修饰的类型为TYPE的变量value是不可变的
* const TYPE value
* TYPE const value
非指针类型
对于非指针的类型TYPE,不论怎么写,都是一个含义,即value只读不可变。
指针类型
- const (char) *pContent;
- (char) const *pContent;
- char* const pContent;
- const char* pContent;
- const char* const pCentent;
对于第一个和第二个,const修饰的类型为char的变量*pContent的常亮,因此pContent的内容为常亮且不可变
对于第三个和第四个,const修饰的类型为char*的变量pContent为常亮,因此,pContent指针本身为常亮不可变
第五个是两种的混合体,表示指针本身和指针内容两者为常亮都不可变
如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向常亮,
如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量
const函数返回值
- const int fun1() 没有意义,因为参数返回本身就是赋值
- const int *func2() 指针内容是不可变
- int* const func2() 指针不可变
mutable
与const相反
为了突破const的限制而设置
被mutable修饰的变量,将永远处于可变的状态,及时再一个const函数中。
如果类的成员函数不会改变对象的状态,那么这个成员函数一般会申明成const。但是,有些时候,需要在const的函数里面修改一些和类状态无关的数据成员,这个数据成员就应该被mutable修饰
const void a()
{
}
如果要在a中修改成员变量;
只需要将变量申明成mutable
宏
发生在预处理阶段的单独的字符替换,没有变量 常亮 语法
程序编译流程
- 预处理(生成.i):gcc -o l.i l.c -E
- 编译(生成.s): gcc -o l.s l.i -S
- 汇编(生成.o): gcc -o l.o l.s -o
- 链接 : gcc -o test l.o
预处理:替换宏,将所有define全部替换
引用
- 引用就是对象的另一个名字
- 引用必须要初始化 //(int &refVal;错误) (int &refVal = val;)
字符串转化
拼装字符
sprintf(char*,char,char);
char newstr[128];
sprintf(newstr,"%s",str);
sprintf(newstr,"fish%02d%_02d.png",2,1);//fish-2_-1.png
sprintf打印到字符串,printf打印到控制台
auto
当一个变量难以确切的知道或者写法很繁难的时候,用关键字auto从该变量的初始化值来推断其类型。
字符串
尾零 ‘\0’ 即便打印也看不见
字符串”h\0”表示’h’和’\0’ 2个字节,1个字符。
strlen
strlen所做的仅仅是一个计数器的工作,它从内存的某个位置(可以使字符串开头,中间某个位置,甚至是不确定的内存区域)开始扫描,知道碰到第一个字符串结束符”\0”位置,然后返回计数器值(长度不包含’\0’)
strlen("h") = 1
strlen("h\0") = 1
char*
//
char *q = "hello";
cout<<q; // "hello";
cout<<*q; //"h"
//将只读数据段hello复制到数组中,栈中空间可以修改,原版的还在只读数据段。
char a[64] = "hello";
char* 和 const char*
char []ch = "afdsf";
char *p = &ch;
const char* cp = &ch;
p[0] = 'd';
cp[0] = 'e'; //error
p = "fsf";
cp = "fsf";//error
可变长参数
c语言的参数是从后往前被堆积在栈中。
由调用方法将参数从栈中除去。无论需要堆积多少个参数,总能找到第一个参数的地址。由于其余的参数是连续排列在第一个参数后面的,所以你可以顺序地将它们取出。
java是从前向后将参数堆积在栈中。这种方式能够从前面开始对参数进行处理,所以比较直观。
一般只有在如果不使用可变长参数地函数,程序写起来就会变的困难地情况下使用可变长参数
&符号
在赋值=的左边表示引用
在赋值的右边表示取地址
与类型在一起时为引用 int function(int &a)
for(;;) while(1)
for(;;)编译成汇编后事无条件转移,while(1)是要0和1进行一下比较,所以从这个方向上看for(;;)要比while(1)快,因为少了一个比较指令,但现在的编译器都有一定的优化能力,会将while(1)优化成for(;;)一样的汇编代码
goto
if(a)
{
goto fail;
}
return 1;
fail:
return 0;
volatile
确保本条指令不会因编译器的优化而省略,且要求每次直接读值
a = 10;
a = 11;
a = 12;
编译器会对上述语句进行优化,只执行最后一句,但是如果输入volatile,编译器会逐一的运行代码并产生相应的机器代码。
当两个线程都要用到某一变量且该变量的值会改变时,应该用volatile声明,防止优化编译器把变量从内存装入CPU寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存的变量,一个使用寄存器中的变量。这回造成程序的错误执行。
volatile的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在在寄存器中的值。
int nMyCounter = 0;
for(;nMyCounter < 100 ; nMyCounter++)
{
...
}
...
在这段代码中,nMyCounter的拷贝可能存放到某个寄存器中(循环中,对nMyCounter的测试以及操作总是对此寄存器中的值进行),但是另外又有端代码执行了这样的操作,nMyCounter -= 1;这个操作中,对nMyCounter的改变是对内存中的nMyCounter进行操作,于是出现了这样一个现象:nMyCounter的改变不同步。
cast转换
dynamic_cast 动态类型转换符 支持多态而存在,主要用于类之间的转换
包括向下转换 将一个指向基类的指针或引用转换成一个指向派生类的指针或引用
向上转换 将一个指向派生类的指针或引用转换成一个指向基类的指针或引用
static_cast 静态类型转换符 仅仅完成编译时期的转换检查
任何类型的指针与void之间的转换
将空指针转换成目标指针类型
用于基本数据类型之间的转换,把int转换成char
reinterpret_cast 再解释类型转换符 完成不同指针之间的相互转换
const_cast 常类型转换符 用来修改类型的const或volatile属性
常类型转换符 const_cast
常类型转换const_cast用来修改类型的const或volatile属性
备忘录
- switch内初始化要用{}包括
- 结构的所有数据成员具有独立的 内存空间
联合的所有数据成员起始于同一个地址