目录
// 宏常量的优势// 1、可以达到一次性一改全改的效果,提高了程序的复用性// 2、可以提高程序的可读性
缺点:1.不方便调试宏。(因为预编译阶段进行了替换)(报错位置不准确)2.导致代码可读性差,可维护性差,容易误用。3.没有类型安全的检查 。编辑
因为宏常量有缺陷,我们在c++的时候用const常量对宏进行了取代
在所有读取a常量中内容的位置,比如打印常量 都会使用使用常量本身替换
值和引用的作为返回值类型的性能比较
这里我们创建了三个函数 分别对传值 传指针 传引用,做以比较
代码如下 :
#include<time.h>
struct SeqList
{
int array[10000];
int size;
};
void TestValue(SeqList s)
{}
void TestPtr(SeqList* ps)
{}
void TestRef(SeqList& s)
{}
void TestTime(int n)
{
SeqList s;
size_t beginVal = clock();
for (int i = 0; i < n; i++)
{
TestValue(s);
}
size_t endVal = clock();
cout << " TestValue :" << endVal - beginVal;
size_t beginPtr = clock();
for (int i = 0; i < n; i++)
{
TestPtr(&s);
}
size_t endPtr = clock();
cout << " TestPtr :" << endPtr - beginPtr;
size_t beginRef = clock();
for (int i = 0; i < n; i++)
{
TestRef(s);
}
size_t endRef = clock();
cout << " TestRef :" << endRef - beginRef << endl;
}
int main()
{
for (int i = 0; i < 10; i++)
{
TestTime(1000000);
}
return 0;
}
结果如下:
我们可以看到值传递与指针和引用传值效率上有很大的差异,在传值的方式体现上,我们必须对实参进行一份拷贝,如果实参非常大,那么拷贝所需要的时间和空间也会是比较大的。
传地址和传指针的效率上差不多
但是传引用更安全,代码可读性更高。
引用初识:引用只是对变量的别名,编译器不会给引用变量重新开辟内存空间,引用与其引用的实体共用一份内存空间
发现:引用实际是有空间的,空间中放的是其引用实体的地址
语法概念:引用就是别名。编译器不会给引用变量开辟空间-->这样方便用户理解
底层实现:要实现引用的技术,底层又把引用换成指针---引用是语法层面的概念。在底层实际没有引用的概念。
指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作
引用 与 指针的转化
定义了int* const cpaa; 在定义时就必须进行初始化,因为指针cpaa的指向在后面将无法修改。
1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
2. 引用在定义时必须初始化,指针没有要求
3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
4. 没有NULL引用,但有NULL指针
5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(程序按32位编译环境下编译出来时占4个字节,按64位编译环境编译下来时占8个字节)
char ch = 'A';
char& rc = ch;
char* pc = &ch;
cout << sizeof(rc) << endl; // 结果为1
cout << sizeof(pc) << endl; // 结果为4
6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
7. 有多级指针,但是没有多级引用
8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
指针需要用户自己解引用,引用在底层都被编译器直接转化为指针的方式进行处理
9. 引用比指针使用起来相对更安全
10.对NULL进行传递
宏
// 宏常量的优势
// 1、可以达到一次性一改全改的效果,提高了程序的复用性
// 2、可以提高程序的可读性
#define MAXSIZE 100
#define PI 3.14
// 宏常量的优势
// 1、可以达到一次性一改全改的效果,提高了程序的可扩展性
// 2、可以提高程序的可读性
int main()
{
int array[MAXSIZE];
for (int i = 0; i < MAXSIZE; ++i)
{
array[i] = i * 10;
}
for (int i = 0; i < MAXSIZE; ++i)
{
cout << array[i] << " ";
}
cout << endl;
double r = 2.0;
cout << PI * r * r << endl;
cout << 2 * PI * r << endl;
return 0;
}
缺点:
1.不方便调试宏。(因为预编译阶段进行了替换)(报错位置不准确)
2.导致代码可读性差,可维护性差,容易误用。
3.没有类型安全的检查 。
因为宏常量有缺陷,我们在c++的时候用const常量对宏进行了取代
// 注意:
// 在C++中,被const修饰的变量不在是变量,而是一个常量
// 在C语言中,被const修饰的变量是一个不能被修改的变量
int array[MAXSIZE];
const int num = 100;
scanf_s("%d", &num); //输入 5
int b[num];
cout << sizeof(b) / sizeof(b[0]) << endl; //输出100
const int n = 100;
int a[n];
小结:
1、宏常量的替换发生在预处理阶段
2、const常量的替换发生在编译阶段
在所有读取a常量中内容的位置,比如打印常量 都会使用使用常量本身替换
int main()
{
const int a = 10;
int* pa = (int*)&a;
*pa = 100;
cout << a << " " << *pa << endl;
cout << 10 << " " << *pa << endl;
}
宏函数
// 宏函数
// 优点:在预处理阶段会展开,(展开:就是用宏体替换宏使用的位置)少了函数调用的开销
// 缺陷:
// 1. 不会进行类型检测
// 2. 不能调试
// 3. 有副作用
// 4. 会造成代码膨胀
#define Add(x,y) (x)*(y)
#define MAX(x,y) (x)>(y)?(x):(y)
int main()
{
cout << Add(1, 2) << endl;
//cout << Add(1, "2") << endl;
cout << Add(1 + 2, 2 + 3) << endl; // (1+2)*(2+3)
int a = 20;
int b = 10;
int ret = MAX(++a, b); // (++a)>(b)?(++a):(b) ++a被执行了俩次
return 0;
}
内联函数
1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用
缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。
2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。
3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数入口地址了,链接就会找不到。inline函数要再当前文件里面展开并使用。(链接报错)
inline int Add(int x, int y)
{
return x + y;
}
int main()
{
int a = 10;
int b = 20;
int ret = Add(a, b);
printf("%d\n", ret);
return 0;
}