格式化
%d:指参数以十进制整型输入or输出 %f:浮点数(float,double)输入or输出(还有%1.2f 等,表示限定小数点前后的位数)
%u:无符号整数 %x:十六进制 %o:八进制 %3d,%-3d,%03d的区别? %3d--可以指定宽度,不足的左边补空格
%-3d--左对齐 %03d---一种左边补0 的等宽格式,比如数字12,%03d出来就是: 012。 %0x跟0x的区别? printf("%x\n",x);得到输出5,printf("%0x\n",x);得到输出05。
左位移与右位移
算术左移:末尾添0;逻辑左移:末尾添0;算术右移:左端最低位填充;逻辑右移:左端添0。
左移:丢弃最高位,0补最低位,例如:
int i = 1;i = i << 2; //把i里的值左移2位
1的2进制是000...0001,左移2位之后变成000...0100,也就是10进制的4,所以说左移1位相当于乘以2,那么左移n位就是乘以2的n次方了。
特殊情况:
1:改变符号位
int i = 0x40000000; //16进制的40000000,为2进制的01000000...0000 i = i << 1;
那么,i在左移1位之后就会变成0x80000000,也就是2进制的100000...0000,符号位被置1,其他位全是0,变成了int类型所能表示的最小值,32位的int这个值是-2147483648,溢出.如果再接着把i左移1位会出现什么情况呢?在C语言中采用了丢弃最高位的处理方法,丢弃了1之后,i的值变成了0.
2:移动位数超过总位数
int i = 1, j = 0x80000000; //设int为32位
i = i << 33; // 33 % 32 = 1 左移1位,i变成2
右移
右移对符号位的处理和左移不同,对于有符号整数来说,比如int类型,右移会保持符号位不变,例如:
int i = 0x80000000;i = i >> 1; //i的值不会变成0x40000000,而会变成0xc0000000
就是说,符号位向右移动后,正数的话补0,负数补1。
总之,在C中,左移是逻辑/算术左移(两者完全相同),右移是算术右移(左边添加的数和符号有关),会保持符号位不变.实际应用中可以根据情况用左/右移做快速的乘/除运算,这样会比循环效率高很多。
数据类型
unsigned若省略后一个关键字,大多数编译器都会认为是unsigned int会被覆盖掉了。
unsigned char与char区别:
在C/C++中char型等价于整型数据,占一个字节,8个比特位。在语言中默认的就是signed char ,其范围对应整数-128~+127,而unsigned char代表的是无符号的字符型,对应的整数范围为0~255.
二维数组
二维数组在c++中存储,一般是按行存储的,就是将一行当作一维数组进行存储。例如 int array[2][2]={{1,2},{3,4}};内存中依次存放着:1 2 3 4。
类跟结构体的区别
C的struct与C++的class的区别:struct只是作为一种复杂数据类型定义,不能用于面向对象编程。
C++中的struct和class的区别:对于成员访问权限以及继承方式,class中默认的是private的,而struct中则是public的。class还可以用于表示模板类型,struct则不行。
i++与++i区别
mov ax,si //si就是i的内容,装载到ax寄存器
inc si //i++;就是内容加一
push ax //压栈
如上,i++是在取得i的值之后马上自加。
inc si //又增加了,刚刚si已经增加了 ++i
mov ax,si //给ax寄存器
push ax
如上,++i是先自加后,再取i的值。
调用约定
函数默认是_cdecl调用约定,加上WINAPI就是_stdcall,之间的区别,详见:http://blog.csdn.net/evsqiezi/article/details/7824496
指针里面*p++和p++有什么区别
p++,表示单纯的指针往后移,后移的大小,根据指针类型定义。
*p++,表示p所指向的指针往后移动1个单位以后,再去p指向的内容。
如int a[4]={4,5,6,7},*p;p=a;printf ("%d",*p++);printf("%d",*p);那前面一个输出结果是4,后面一个的输出结果是5。
头文件跟源文件的关系
所谓的编译只编译cpp文件,.h文件不参与编译,头文件的作用就是告诉编译器,有这个类,但是类的实现在其他位置,编译时,编译器不会去找类的实现,链接时编译器才会去寻找这个类的实现。
宏跟函数的区别
1. 宏做的是简单的字符串替换(注意是字符串的替换,不是其他类型参数的替换),而函数的参数的传递,参数是有数据类型的,可以是各种各样的类型.
2. 宏的参数替换是不经计算而直接处理的,而函数调用是将实参的值传递给形参,既然说是值,自然是计算得来的.
3. 宏在编译之前进行,即先用宏体替换宏名,然后再编译的,而函数显然是编译之后,在执行时,才调用的.因此,宏占用的是编译的时间,而函数占用的是执行时的时间.
4. 宏的参数是不占内存空间的,因为只是做字符串的替换,而函数调用时的参数传递则是具体变量之间的信息传递,形参作为函数的局部变量,显然是占用内存的.
5. 函数的调用是需要付出一定的时空开销的,因为系统在调用函数时,要保留现场,然后转入被调用函数去执行,调用完,再返回主调函数,此时再恢复现场,这些操作,显然在宏中是没有的.
宏中"#"和"##"的用法
我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.
宏中的自增
在宏调用时,如果有自增(++)或自减(--)操作符,一定要注意很可能会产生副作用。因为宏在替换时,如果变量出现了多次,就相当于自增或自减操作进了多次,这个跟函数调用是完全不同的,函数调用中形参会复制实参的数值,并对形参进行操作并不会影响实参,而宏调用就是直接多次修改实参。