程序员面试精要-C/C++程序设计-预处理/const/sizeof(面试宝典读书笔记)

宏定义

1.宏定义展开容易造成二义性问题

#define SQR(x) (x*x)

a =SQR(b+2)展开后为b+2*b+2而不是”(b+2)*(b+2)”

若要平方形式对表达式适用,可以把宏定义改为

#define SQR(x) ((x)*(x))

 

Const

2.const有什么用途?

在C程序中,const的用法主要有定义常量,修饰函数蚕食,修饰函数返回值等三个用处。在C++程序中,它还可以修饰函数的定义体,定义类中某个成员函数为恒态函数,即不改变类中的数据成员。

被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

3.const与#define相比有什么不同

const常量有数据类型,而红常量没有数据类型。编译器可以对前者进行安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料不到的错误(边际效用)

有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。在C++程序中只使用const常量而不是用宏常量,即const常量完全取代宏常量(这里我也纠结了~~原文上面还说也可以使用#define定义常量来着,只是const有更多有点)

C中const的意思是“一个不能被改变的普通变量”。在C中,它总是占用内存,而且它的名字是全局符。C编译器不能把const看成一个编译期间的常量。在C中,如果写:

const bufsize=100;

char buffer[bufsize];

将得到错误结果。因为bufsize占用内存的某个地方,所以C编译器不知道它在编译时的值。在C语言中可以选择这样书写:

const bufsize;

这样写在C++中是不对的,而C编译器则把它作为一个声明,这个声明指明在别的地方有内存分配。因为C默认const是外部连接,C++默认const是内部连接的。如果在C++中要完成与C同样的事情,必须用extern把内部连接改为外部连接。extern constbufsize;//declaration only

这种方法也可以用在C语言中。在C语言中使用限定符const不是很有用,即使是在常数表达式里(必须在编译期间被求出)想使用一个已命名的值,使用cosnt也不是很有用。C迫使程序员在预处理器里使用#define。

 

Sizeof

指针的大小是一个定值,4

在默认情况下,为了方便对结构体内元素的访问和管理,当结构体内的元素的长度都小于处理器的位数的时候便一结构的里面最长的数据元素为对其单位,即结构体的长度一定是最长的数据元素的整数倍。如果结构体内存在长度大于处理器位数的元素,那么就以处理器的位数为对其单位。但是结构体内类型相同的连续元素将在连续的空间内,和数组一样。

CPU的优化规则大致原则是这样的:对于n字节的元素(n=2,4,8…),它的首地址能被n整除,才能获得最好的性能。设计编译器的时候可以遵循这个原则:对于每一个变量,可以从当前位置向后找到第一个满足这个条件的地址作为首地址。

对于一个类,即使它是一个空类,编译器仍然要给它一个空间,大小为1.

单一继承的空类空间也是1,多重继承的空类空间也是1.但是虚继承涉及到虚表(徐指针),大小为4

静态变量是存放在全局数据区的,而sizeof计算栈中分配的大小

Ps:

char* ss=”0123456789”;

sizeof(ss)=4ss是指向字符串常量的字符指针)

sizeof(*ss)=1*ss是第一个字符)

 

char ss[]=”0123456789”;

sizeof(ss)=11ss是数组,计算到’\0’位置,因此是10+1

sizeof(*ss)*ss是第一个字符)

 

char ss[100]=”0123456789”;

sizeof(ss)=100(ss表示内存中预分配的大小)

strlen(ss)=10(它的内部实现是用一个循环计算字符串的长度,直到”\0”为止)

 

int ss[100]=”0123456789”;

sizeof(ss)=400(100×4)

strlen(ss)错误(strlen的参数只能是char*,而且必须是以”\0”结尾的)

 

1.说明sizeof和strlen之间的区别

sizeof操作符的结果类型是size_t,它在头文件中的typedef为unsigned int 类型。该类型保证能容纳实现所建立的最大对象的字节大小。

sizeof是算符,strlen是函数

sizeof可以用类型做参数,strlen 只能用char*做参数,而且必须以”\0”结尾的。Sizeof还可以用函数做参数。

数组做sizeof的参数不退化,传递给strlen 就退化为指针。

大部分编译程序在编译的时候就把sizeof 计算过了,是类型或是变量的长度。这就是sizeof(x)可以用来定义数组维数的原因。

strlen的结果要在运行的时候才能计算出来,用来计算字符串的长度,而不是类型站内存的大小。

sizeof后如果是类型必须加括号,如果是变量名可以不加括号。这是因为sizeof是个操作符而不是函数。

当使用了一个结构类型或变量时,sizeof返回实际的大小。当使用一个静态的空间数组时,sizeof返回全部数组的尺寸。Sizeof操作符不能返回动态分配的数组或外部的数组的尺寸。

数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址。在C++里传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小。如果在函数内知道数组的大小,需要进入函数后用用memcpy将数组拷贝出来,长度由另一个形参传进去。

fun (unsigned char *p1,int len)

{

      unsigned char* buf=new unsigned char[len+1];

      memcpy(buf,p1,len);

}

计算结构变量的大小必须讨论数据对齐问题。为了使CPU存取的速度最快,C++在处理数据时经常把结构变量中的成员的大小按照4或8的倍数计算,这就叫数据对齐(data alignment)。这样做可能会浪费一些内存,但在理论上CPU速度更快了。当然,这样的设置会在读写一些别的应用程序生成的数据文件或交换数据时带来不便。MS VC++中的对其设定,有时候sizeof得到的与实际不符。一般在VC++中加上#pragma pack(n)的设定即可。或者如果要按字节存储,而不进行数据对齐,可以在Options对话框中修改Adcanced Complier选项卡中的“Data Alignment”为按字节对齐。

sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小数据的数据类型。

2. sizeof的使用场合

sizeof操作符的一个主要用途就是与存储分配和I/O系统那样的例程进行通信。

用它可以看看某种类型的对象在内存中所占的单元字节。

在动态分配一对象时,可以让系统知道分配多少内存(我怎么感觉这说法有点矛盾?求证)

便于一些类型的扩充。在Windows中有很多结构类型就有一个专用的字段来存放该类型的字节大小(这个跟sizeof嘛关系???)。

由于操作数的字节数在实现时可能出现变化,在涉及到操作数字节大小时使用sizeof代替常量有明显优势。

如果操作数是函数中的数组形参或参数类型的形参,sizeof给出其指针的大小。

 

内存中的数据对齐

数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍。DWORD数据的内存地址能被4除尽,WORD数据的内存起始地址能被2除尽。X86 CPU能直接访问对其的数据,当它试图访问一个未对其的数据时,会在内部进行一系列的调整。这些调整对于程序来说是透明的,但是会降低运行速度,所以编译器在编译程序时会尽量保证数据对齐。


内联函数和宏定义

1.内联函数和宏的差别是什么

内联函数和普通函数相比可以加快程序运行的速度,因为不需要中断调用,在编译的时候内联函数可以直接被镶嵌到目标代码中,而宏只是一个简单的替换。

内联函数要做参数类型检查(优势)

Inline是指嵌入代码,就是在调用函数的地方不是跳转,而是把代码直接写到调用处。对于短小的代码来说,inline可以带来一定的效率提升,而且和C时代的宏函数相比,inline 更安全可靠(以增加空间消耗为代价)。

Inline一般只用于如下情况:

1)一个函数不断被重复调用

2)函数只有简单的几行,而且函数内不包含for while switch语句

一般来说,我们写小程序没有必要定义成inline,但是如果要完成一个工程项目,当一个简单函数被调用多次时,应该考虑用inline。

宏在C语言里极重要(C++中就不是了)。关于宏的第一规则是:绝不应该去使用它,除非你不得不这样做(这是多招人嫌啊)。几乎每个宏都表明了程序设计语言里或者程序里或者程序员的一个缺陷,因为它将在编译器看到程序的正文之前重新摆布这些正文。

宏是在代码不不加任何验证的简单替代,而内联函数是将代码直接插入调用处,而减少普通函数调用时的资源消耗(我知道有些重复了,当小结吧,笔试由最后这两段就够了)。

宏不是函数,只是在编译前(编译预处理阶段)将程序中有关字符串替换成宏体。


你可能感兴趣的:(面试,c++,读书笔记,编程,语言)