第二章
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第二章相关的知识,希望对你有一定的参考价值。
Z2S2
用#define实现宏并求最大值和最小值
1 #define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )
2 #define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )
在宏中需要把参数小心地用括号括起来。因为宏只是简单的文本替换,如果不注意,很容易引起歧义。
Z2S6
用宏定义得到一个数组所含的元素个数
#define ARR_SIZE(a) (sizeof((a)) / sizeof((a[0])))
假设一个数组定义如下。
int array[100];
它含有100个int型的元素。如果int为4个字节,那么这个数组总共有400个字节。sizeof(array)为总大小,即400个字节;sizeof(array[0])为一个int大小,即4个字节。两个大小相除就是 100,也就是数组的元素个数。这里,为了保证宏定义不会发生“二义性”,在a以及a[0]上都加了括号。
Z2S7
找错——const的使用
1 #include <stdio.h> 2 3 4 5 int main() 6 7 { 8 9 const int x = 1; 10 11 int b = 10; 12 13 int c = 20; 14 15 const int* a1 = &b; 16 17 int* const a2 = &b; 18 19 const int* const a3 = &b; 20 21 x = 2; 22 23 //a1定义为const int*类型,注意这里的const在int*的左侧,它是用修饰指针所指向的变量,即指针指向为常量。故 a1 指向变量 c是允许的,因为这修改的是指针a1本身。 24 25 a1 = &c; 26 27 //但改变a1指向的内容是不允许的。 28 29 *a1 = 1; 30 31 //a2定义为int* const类型,注意这里的const在int*的右侧,它是用修饰指针本身,即指针本身为常量。因此下行中修改指针 a2 本身是不允许的。 32 33 a2 = &c; 34 35 //但修改a2指向的内容是允许的。 36 37 *a2 = 1; 38 39 //a3 定义为const int* const类型,这里有两个const,分别出现在int*的左右两侧,因此它表示不仅指针本身不能修改,并且其指向的内容也不能修改。所以下面2行都会出现编译错误。 40 41 a3 = &c; 42 43 *a3 = 1; 44 45 return 0; 46 47 } 48 49 //注意:变量x、a2和a3在声明的同时一定要初始化,因为它们在后面都不能被赋值。而变量a1可以在声明的时候不初始化。
Z2S8
说明const与#define的特点及区别
#define只是用来做文本替换的。#define常量是一个Compile-Time概念,它的生命周期止于编译期,它存在于程序的代码段,在实际程序中它只是一个常数、一个命令中的参数,并没有实际的存在。
const常量存在于程序的数据段,并在堆栈分配了空间。const常量是一个Run-Time的概念,它在程序中确确实实地存在着并可以被调用、传递。const常量有数据类型,而宏常量没有数据类型。编译器可以对const常量进行类型安全检查。
Z2S9
C++中const有什么作用
(1)const用于定义常量:const定义的常量编译器可以对其进行数据静态类型安全检查。
(2)const修饰函数形式参数:当输入参数为用户自定义类型和抽象数据类型时,应该将“值传递”改为“const &传递”,可以提高效率。比较下面两段代码:
1 void fun(A a);
2 void fun(A const &a);
第一个函数效率低。函数体内产生A类型的临时对象用于复制参数a,临时对象的构造、复制、析构过程都将消耗时间。
而第二个函数提高了效率。用“引用传递”不需要产生临时对象,节省了临时对象的构造、复制、析构过程消耗的时间。但光用引用有可能改变a,所以加const。
(3)const修饰函数的返回值:如给“指针传递”的函数返回值加const,则返回值不能被直接修改,且该返回值只能被赋值给加const修饰的同类型指针。例如。
1 const char *GetChar(void){};
2 char *ch = GetChar(); // error
3 const char *ch = GetChar(); // correct
(4)const修饰类的成员函数(函数定义体):任何不会修改数据成员的函数都应用const修饰,这样,当不小心修改了数据成员或调用了非const成员函数时,编译器都会报错。
const修饰类的成员函数形式为:
int GetCount(void) const;
Z2S10
static有什么作用
在C语言中,关键字static有3个明显的作用:
(1)在函数体,一个被声明为静态的变量在这一函数被调用的过程中维持其值不变。
(2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所有函数访问,但不能被模块外其他函数访问。它是一个本地的全局变量。
(3)在模块内,一个被声明为静态的函数只可被这一模块内的其他函数调用。那就是这个函数被限制在声明它的模块的本地范围内使用。
Z2S11
static全局变量与普通的全局变量有什么区别
static全局变量与普通全局变量的区别是,static全局变量只初始化一次,防止在其他文件单元中被引用。(作用域不同,静态全局变量只在当前源文件内有效)
static局部变量和普通局部变量的区别是,static局部变量只被初始化一次,下一次依据上一次结果值。(生存期不同)
static函数与普通函数的区别是,static函数在内存中只有一份,普通函数在每个被调用中维持一份复制品。(作用域不同)
Z2S13
使用sizeof计算普通变量所占空间大小
void Func ( char str[100] )
{
//str 是函数的参数,它在做sizeof 运算时被认为是指针。这是因为当我们调用函数 Func(str)时,由于数组是“传址”的,程序会在栈上分配一个4字节的指针来指向数组,因此结果也是4。
sizeof(str) = ____;
}
void *p = malloc(100);
//p 首先指向一个100 字节的堆内存。这里还是对指针做sizeof 运算,结果仍然是4。
sizeof(p) =______;
Z2S15
使用sizeof计算含有虚函数的类对象的空间大小
普通函数不占用内存,只要有虚函数,就会占用一个指针大小的内存,原因是系统多用了一个指针维护这个类的虚函数表,并且注意这个虚函数无论含有多少项(类中含有多少个虚函数)都不会再影响类的大小。
Z2S20
使用sizeof计算联合体的大小
union u2
{
char a[13];
int b;
};
对于 u2 来说,最大的空间是 char[13]类型的数组。这里要注意,由于它的另一个成员int b 的存在,u2 的对齐方式变成4,也就是说,u2 的大小必须在4的对齐上,所以占用的空间变为最接近13的对齐,即16。
以编译器会尽量把数据放在它的对齐上以提高内存的命中率。对齐是可以更改的,使用#pragma pack(x)可以改变编译器的对齐方式。C++固有类型的对齐取编译器对齐方式与自身大小中较小的一个。
例如,指定编译器按 2 对齐,int类型的大小是4,则int的对齐为2和4中较小的2。
Z2S23
内联函数相比于宏定义的优越之处
inline定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换(像宏一样展开),没有了调用的开销,效率也很高。
类的内联函数也是一个真正的函数。编译器在调用一个内联函数时,首先会检查它的参数的类型,保证调用正确;然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。
inline 可以作为某个类的成员函数,当然就可以在其中使用所在类的保护成员及私有成员。
Z2S25
为什么不把所有的函数都定义成内联函数
内联是以代码膨胀(复制)为代价的,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。以下情况不宜使用内联。
如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
另外,类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。
所以不要随便地将构造函数和析构函数的定义体放在类声明中。一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这说明了 inline 不应该出现在函数的声明中)。
Z2S26
理解内联函数与宏定义的区别
内联函数在编译时展开,宏在预编译时展开
在编译的时候,内联函数可以直接被镶嵌到目标代码中,而宏只是一个简单的文本替换。
内联函数可以完成诸如类型检测、语句是否正确等编译功能,宏就不具备这样的功能。
宏不是函数,inline函数是函数。
宏在定义时要小心处理宏参数(一般情况是把参数用括号括起来),否则容易出现二义性。而内联函数定义时不会出现二义性。
以上是关于第二章的主要内容,如果未能解决你的问题,请参考以下文章