分类:
2012-02-15 11:17:21
(
6.1 宏定义(1)用宏定义FIND来定义一个结构体struc里某个变量相对struc的偏移量。
Eg: struct student{ int a, char b[20], double ccc};
FIND(student, a)=0; FIND(student, b)=4;
Notes:
A: #define FIND(struc, e) ((size_t)&(((struc*)0)->e))
(struc*)0 表示将常量0强制转换成struc* 型指针所指向的地址, &(((struc*)0)->e)表示取结构体指针(struc*)0的成员e的地址,因其首地址为0,故可得成员e距离结构体首地址的偏移量。Size_t为一个基本的无符号整数的C / C + +类型。 它是sizeof操作符返回的结果类型。在C++中,设计 size_t 就是为了适应多个平台的 。size_t的引入增强了程序在不同平台上的可移植性。size_t是针对系统定制的一种数据类型。
(2)用宏定义声明一个常数表明一年中有多少秒(忽略闰年问题)。
Notes:
A: #define SECONDS_PER_YEAR (365*24*60*60UL)
a. 使用括号 b.名字定义 c.考虑溢出用长整型
(3)用宏定义实现取两个参数中较小的一个:
A: #define MIN(A,B) ((A)<=(B) ? (A) : (B))
6.2 const(1)const 作用:、
a. 可以定义常量。b.可以修饰函数参数和返回值,甚至函数的定义体,被const修饰后,受到强制保护,可以预防意外的变动,提高程序健壮性。
(2)const较之于宏定义的优点:
a. const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只有字符替换,可能产生意料不到的错误。
b.在const常量便于追踪,可调试,宏常量不便调试。
(3)const var; 在c中是对的,c编译器把它看作一个声明,这个声明指明在别的地方有内存分配;而在c++中编译无法通过,常量必须在定义时初始化!c默认const是外部链接的,c++默认const是内部链接的,为了在c++中完成同样的事情必须用extern将内部链接改成外部链接: extern const var; 在c中最好用宏定义,在c++用const声明常量。
(4)在c++中,类中的函数用const修饰了,则此函数为恒态函数,不可以改变类中的数据成员。如果确实要改变,则在数据成员前用mutable 修饰。
6.3 sizeof(1)
struct {short a1; short a2; short a3;}A;
struct{long a1; short a2;}B;
class C{double d; float f; int i; short s; char c;};
class D{int a; static int b;};
class E{private: bool a; int b; bool c;};
class F{private: int b; bool a; bool c;};
int main()
{
char* ss1 = "0123456789";
char ss2[] = "0123456789";
char ss3[100] = "0123456789";
int ss4[100];
char q1[]="abc";
char q2[]="a\n";
char* q3="a\n";
char *str1 = (char*)malloc(100);
void *str2 = (void*)malloc(100);
cout<
cout<
cout<
cout<
cout<
cout<
cout<
cout<
cout<
cout<
cout<
cout<
cout<
//静态变量存放在全局数据区,不被计算
cout<
cout<
int i = 1;
cout<
return 0;
}
Notes:
结构体的内存空间:
a. 当结构体内元素的长度都小于处理器的位数时:
以结构体内最长的数据元素为对齐单位,即结构体的长度一定是最长数据元素的整数倍。
b. 当结构体内存在长度大于处理器位数的元素时,以处理器的位数为对齐单位,但是结构体内类型相同的连续元素将在连续的空间内。
内存中的数据对齐:
数据对齐是指,数据所在的内存地址是该数据长度的整数倍。Eg: DWORD数据的内存起始地址能被4整除,WORD数据的内存起始地址能被2整除。
禁用数据对齐:在vc中可以用pack指令禁止对齐调整:#param pack(1) struct astruct{char c; int i;} #param pack() … cout<
一般禁用调整会影响程序性能,常用情况是:
a.这个结构需存入文件 b.这个结构需要通过网络传播
(2)sizeof的使用场合:
a.查看某种类型的对象在内存中所占的单元字节
b.动态分配一对象时,使系统知道要分配多少内存
c.操作数的字节数在实现时可能出现变化,可用sizeof代替常量计算
d.与存储分配和I/O系统那样的进程通信: void * malloc(size_t size); size_t fread(void *ptr,size_t size,size_t n,FILE * stream);
(3)sizeof 和 strlen的区别:
a. sizeof 用来计算操纵数所占内存大小,strlen用来计算字符串长度。sizeof不是函数也不是一元运算符,是个类似于宏定义的特殊关键字。sizeof()括号内的内容在编译过程中不被编译,只是被替代为类型。eg: int a = 8; cout<
strlen 的内部实现为:用一个循环计算字符串的长度,直到遇到“\0”为止。
sizeof 可以看作算符,strlen是函数,故strlen后面必须加括号,而sizeof后面跟类型时需加括号,跟变量名时不需加括号。
b.sizeof 可以用类型、变量名、甚至函数作参数,strlen只能用以“\0”结尾的char*作参数。char fun(); cout<
c.sizeof的结果类型为size_t,它在头文件中被typedef为unsigned int
d.数组做参数传递给sizeof时不退化,传递给strlen时退化为指针:char ch[15]=”123”;
cout<
e.unsigned影响的是最高位bit的意义,数据长度不会被改变,sizeof(unsigned type) = sizeof(type),有个例外:vc 6.0 中, cout<
cout<
f.一般在编译时就计算过sizeof了,运行时才知道strlen的结果。
g.sizeof不能用于不完全类型或位字段。不完全类型是指具有未知存储大小数据的数据类型,如未知存储大小的数组、结构、联合以及void类型。
(4)数组作为参数传递到函数内时,退化为一个指针。
(5)class A{};
class A1{};
class B: public A{};
class C: public virtual B{};
class D: public A,public A1{};
void main()
{
cout<
cout<
cout<
cout<
}
Notes:
一个空类所占的空间为1,一个单一继承的空类空间也为1,多重继承的空类空间也未1,但是虚继承因涉及到虚表(虚指针),所占的空间为4。
(6)
string strArr[]={"hello","jia","leo"};
string *pStrArr=new string[2];
pStrArr[0] = "CN";
pStrArr[1] = "US";
cout<
cout<
cout<
for(int i=0; i
{cout<
for(int j=0; j
{cout<
for(int k=0; k<sizeof(*pStrArr)*2/sizeof(string); k++)
{cout<
内联函数是在编译时直接将函数体嵌入到目标代码中,不用中断,减少了函数调用的开销,可提高程序运行效率。适用情况是a.函数被重复调用b.函数短小简单,一般不含for/switch/while函数。
宏是在编译前将相关字符串替换成宏体,只是简单替换没有验证。
内联函数比宏的优势是,要做类型检查。