做篮球网站用的背景图,黄骅港神华集团招聘信息,建设维护网站 未签订合同,公众号小程序制作步骤目录 一#xff0c;概念
二#xff0c;特性
三#xff0c;与内联有关的面试题
四#xff0c;auto关键字#xff08;C11#xff09;
auto的使用细则
auto 不能推导的场景
基于范围的for循环#xff08;C11#xff09;
范围for的使用条件
五#xff0c;指针空值…目录 一概念
二特性
三与内联有关的面试题
四auto关键字C11
auto的使用细则
auto 不能推导的场景
基于范围的for循环C11
范围for的使用条件
五指针空值nullptr(C11) 一概念
以inline修饰的函数叫做内联函数编译时C编译器会在调用内联函数的地方展开没有函数调用建立栈帧的开销内联函数提升程序运行的效率。
如果在函数前增加inline关键字将其改为内联函数在编译期间编译器会用函数体替换函数的调用。
二特性
1inline是一种以空间换时间的做法如果编译器将函数当成内联函数处理在编译阶段会用函数体替换函数调用缺陷可能会使目标文件变大优势少了调用开销提高程序运行效率。
2.inline对于编译器而言只是个建议不同编译器关于inline实现机制可能不同一般建议将函数规模较小即函数不是很长具体没有准确的说法取决于编译器内部的实现不是递归频繁调用的函数采用inline修饰否则编译器会忽略inline特性。 《Cprime》第五版内联说明只是向编译器发出的一个指令编译器可以选择忽略这个请求。 一般来说内联机制用于优化规模较小流程直接频繁调用的函数。很多编译器都不支持内联递归函数而且一个75行的函数也不大可能在调用点内联地展开。 3inline不建议声明和定义分离分离会导致链接错误。因为inline被展开,就没有函数地址了链接就会找不到。
//test.h
#includeiostream
using namespace std;
inline int Add(int left, int right);//fun.cpp
#includetest.h
int Add(int left, int right)
{return left right;
}//test.cpp
#includetest.h
int main()
{int ret 0;ret Add(1, 2);return 0;
}
//链接错误 LNK2019 无法解析的外部符号 int __cdecl Add(int,int) (?AddYAHHHZ)函数 main 中引用了该符号
三与内联有关的面试题
宏的优缺点
优点1增强代码的复用性 2提高性能
缺点1不方便调试宏因为预编译阶段进行了替换2导致代码可读性差可维护性差容易误用。3没有类型安全的检查
C有哪些技术替代宏
1常量定义 换用const enum
2短小函数定义换成内联函数
四auto关键字C11
简介
在早期C\C中auto的含义是使用auto修饰的变量是具有自动存储器的局部变量。而在C11中标准委员会赋予了auto全新的含义即auto不再是一个存储类型指示符而是作为一个新的类型指示符来指示编译器auto声明的变量必须由编译器在编译时期推导而得。
#includetest.h
int TestAuto()
{return 10;
}
int main()
{int a 10;auto b a;auto c a;auto d TestAuto();cout typeid(b).name() endl;//typeid(x).name() :打印x类型cout typeid(c).name() endl;cout typeid(d).name() endl;//auto e; 无法编译通过使用auto定义变量时必须对其初始化return 0;
}
注意使用auto定义变量时一定要对齐初始化在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明而是一个类型声明时的“占位符”编译器在编译期会将auto替换为变量实际的类型。
auto的使用细则
1auto与指针和引用结合起来使用
用auto声明指针类型时用auto和auto*没有任何区别但用auto声明引用类型时必须加
int main()
{int x 10;auto* a x;auto b x;auto c x;cout typeid(a).name() endl;cout typeid(b).name() endl;cout typeid(c).name() endl;return 0;
}
2在同一行定义多个变量
当在同一行声明多个变量时这些变量必须是相同的类型否则编译器将会报错因为编译器实际只对第一个类型进行推导然后用推导出来的类型定义其他变量。
void TestAuto2()
{auto a 1, b 2;//auto c 3, d 4.0; 该行代码会编译失败因为C和D的初始化表达类型不同。
}
auto 不能推导的场景
1auto不能作为函数的参数
//此处编译失败auto不能作为形参类型因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}
2 auto不能直接用来声明数组
void TestAuto()
{int a[] {1,2,3};auto b[] {4,5,6};//错误
}
3为了避免与C98中的auto发生混淆C11只保留了auto作为类型指示符的用法
4auto在实际中最常见的优势用法就是跟新式for循环,还有lambda表达式等进行配合使用。
基于范围的for循环C11
范围for的语法
在C98中如果要遍历一个数组可以按照以下方式进行
void TestFor()
{int array[] { 1,2,3,4,5 };for (int i 0; i sizeof(array) / sizeof(array[0]); i)array[i] * 2;for (int* p array; p array sizeof(array) / sizeof(array[0]); p)cout *p endl;
}
对于一个有范围的集合而言由程序员来说明循环的范围是多余的有时候还会容易犯错误因此C11中引入了基于范围的for循环。for循环后的括号由“”分为两部分第一部分是范围内用于迭代的变量第二部分则表示被迭代的范围。
void TestFor()
{int array[] { 1,2,3,4,5 };for (auto e : array){e * 2;}for (auto e : array)cout e ;}
注意与普通循环类似可以用continue来结束本次循环也可以用break来跳出整个循环。
范围for的使用条件
1for循环迭代的范围必须是确定的
对于数组而言就是数组中第一个元素和最后一个元素的范围对于类而言应该提供begin和end的方法begin和end就是for循环迭代的范围。
注意以下代码就有问题因为for的范围不确定
void TestFor(int array[])
{for(auto e; array)couteendl;
}
2迭代的对象要实现和的操作。
五指针空值nullptr(C11)
C98中的指针空值
在良好的c\c编程习惯中声明一个变量时最好给变量一个合适的初始值否则可能出现不可预料的错误比如未初始化的指针。如果一个指针没有合法的初始值我们基本是按照如下方式对其进行初始化
void TestPtr()
{int* p1 NULL;int*p2 0;
}
NULL实际上是一个宏在传统的C头文件stddef.h中可以看到如下代码
#ifndef NULL
#ifdef _cplusplus
#define NULL 0;
#else
#defint NULL ((void *)0)
#endif
#endif可以看到NULL可能被定义为字面常量0或者被定义为无类型指针void*的常量。不论采取何种定义在使用空值的指针时都不可避免的会遇到一些麻烦比如 void f(int)
{coutf(int)endl;
}
void f(int*)
{coutf(int*)endl;
}
int main()
{f(0);f(NULL):f((int*)NULL);return 0;
}
程序本意是想通过f(NULL)调用指针版本的int*函数但是由于NULL被定义成0因此与程序的初衷相悖。
在C98中字面常量0既可以是一个整形数字也可以是无类型的指针void*常量但是编译器默认情况下将其看成是一个整形常量如果要将其按照指针方式来使用必须对其进行强转void*0。 注意 1在使用nullptr表示指针空值时不需要包含头文件因为nullptr是C作为新关键字引入的。 2在C中sizeof(nullptr)与sizeof((void*)0)所占的字节相同。 3为了提高代码的健壮性在后续表示指针空值时建议最好使用nullptr。