1、用一个FIND宏定义求一个结构体struc里某个变量相对于struct的偏移量
#define FIND(struc,e) (size_t)&(((struc *)0)->e)
(size_t)是一种数据类型,为了便于不同系统之间移植,最好定义为一种无符号类型数据,一般为unsigned int。(P49)
2、const和#define相比有什么不同?
C++语言可以用const定义常量,也可以用#define定义常量,但是前者比后者更多优点:
(1)const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意想不到的错误(边际效应)。
side effects可以理解成副作用,
当如下调用该宏时:max(a++,b++);宏被替换成 ((a++)>(b++)?(a++): (b++));所以肯定有个变量被计算2次。
(2)有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。在C++中使用const常量而不使用宏常量,即const常量完全取代宏常量。
(3)C 编译器不能把const看成一个编译期间的常量。在C中,如果写:
#include <iostream> using namespace std; int main(void) { const a = 20; int b[a]; return 0; }
尽管看起来像是做了一件合理的事,但这将得到一个错误的结果。因为bufsize占用内存的某个地方,所以C编译器不知道它在编译时的值(P51)
3、在VC中,我们可以用 pack 预处理指令来禁止对齐调整。
pack:
http://www.sf.org.cn/Article/base/200509/260.html
请注意:除非你觉得必须这样,不要轻易做这样的调整,因为这将降低程序性能。目前比较常见的用法是:一,这个结构需要被指接写入文件;二,这个结构需呀哦通过网络传给其他程序。
#include <iostream> using namespace std; #pragma pack(8) struct s1{ short a; long b; }; struct s2{ char c; s1 d; long long e; }; #pragma pack() int main(void) { cout<<sizeof(s2)<<endl; return 0; }
答案为24。(P55)
4、数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍。
struct
{
long a1;
short a2;
};
CPU的优化规则大致原则是:对于n字节的元素(n=2,4,8,...),它的首地址能被n整除,才能获得最好的性能。设计编译器的时候可以遵循这个原则:对于每一个变量,可以从当前位置向后找到第一个盲足这个条件的地址作为首地址。例子比较特殊,因为即便采用这个原则,得到的结果也应该为6字节(long的首地址偏移量为0000,short首地址偏移量0004,都符合要求)。但是结构体一般会面临数组分配的问题。编译器为了优化这种情况,干脆把它的大小设为8字节,这样就没有麻烦了,否则得话,会出现单个结构体的大小为6字节,而大小为n的结构体数组大小却为8*(n-1)+6的尴尬局面。(P53)
5、静态变量是存放在全局数据区的,sizeof计算栈中分配的大小。(P57)
6、sizeof 和 strlen的深入理解
(1)sizeof 操作符的结果类型是size_t,它在头文件中的 typedef 为 unsigned int 类型,该类型保证能容纳实现所建立的最大对象的字节大小。
(2)sizeof 是算符,strlen是函数。
(3)sizeof 可以用类型作参数,strlen 只能用char*作参数,且必须是以"/0"结尾的。sizeof 还可以用函数作参数:
#include <iostream> using namespace std; short f(void); int main(void) { cout<<sizeof(f())<<endl; return 0; }
输出的结果是sizeof(short),即2。
(4)数组作 sizeof 的参数不退化,传递给strlen就退化为指针。
数组名退化(即数组名退化为指针):
http://hi.baidu.com/%CC%EC%B5%D8%D3%D0%C7%E9%CC%EC%D2%E0%C0%CF/blog/item/bd228d3c0994920bbba1675e.html
(5)大部分编译程序在编译的时候就把 sizeof 计算过了,是类型或是变量的长度。这就是 sizeof(x) 可以用来定义数组维数的原因。
(6) strlen 的结果要在运行的时候才能计算出来,用来计算字符串的长度,而不是类型占内存的大小。
(7) sizeof 后如果是类型必须加括号,如果是变量名可以不加括号。这是因为 sizeof 是个操作符而不是个函数
#include <iostream> using namespace std; int main(void) { int a; cout<<sizeof a<<endl; return 0; }
(8)当使用了一个结构类型或变量时,sizeof返回实际的大小。当使用一静态的空间数组时,sizeof 返回全部数组的尺寸。sizeof 操作符不能返回被动态分配的数组或外部的数组的尺寸。
(9)数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址。在C++里传递数组永远都是传递指向数组首元素的指针,便一起不知道数组的大小。如果想在函数内知道数组的大小,需要这样做:进入函数后用 memcpy 将数组复制出来,长度由另一个形参传进去。
memcpy: void * memcpy ( void *destination,const void * source, size_t num);
10、#include <iostream> #include <memory.h> #include <assert.h> using namespace std; class A { }; class A2 { }; class B : public A { }; class C : public virtual B { }; class D : public A,public A2 { }; int main() { cout<<"sizeof(A):"<<sizeof(A)<<endl; cout<<"sizeof(B):"<<sizeof(B)<<endl; cout<<"siziof(C):"<<sizeof(C)<<endl; cout<<"sizeof(D):"<<sizeof(D)<<endl; return 0; }
空类所占的空间为1,单一继承的空类空间也为1,多重继承的空类空间还是1。但是虚继承涉及到虚表(虚指针),所以sizeof(C)的大小为4。