马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
一、编译预处理
C++程序编译的过程:预处理 -> 编译(优化、汇编)-> 链接
预处理指令重要有以下三种:
- 包含头文件:#include
- 宏定义:#define(定义宏)、#undef(删除宏)。
- 条件编译:#ifdef、#ifndef。
1)包含头文件
#include 包含头文件有两种方式:
- #include <文件名>:直接从编译器自带的函数库目录中探求文件。
- #include "文件名":先从自定义的目录中探求文件,如果找不到,再从编译器自带的函数库目录中探求。
#include也包含别的的文件,如:.h、.cpp或别的的文件。
C++98标准后的头文件:
- C的标准库:老版本的有.h后缀;新版本没有.h的后缀,增长了字符c的前缀。例如:老版本是<stdio.h>,新版本是<cstdio>,新老版本库中的内容是一样的。在程序中,不指定std命名空间也能利用库中的内容。
- C++的标准库:老版本的有.h后缀;新版本没有.h的后缀。例如:老版本是<iostream.h>,新版本是<iostream>,老版本已弃用,只能用新版本。在程序中,必须指定std命名空间才能利用库中的内容。
注意:用户自定义的头文件还是用.h为后缀。
2)宏定义指令
无参数的宏:
有参数的宏:
- #define MAX(x,y) ((x)>(y) ? (x) : (y)) MAX(3,5) ((3)>(5) ? (3) : (5))
复制代码 编译的时间,编译器把程序中的宏名用宏内容替换,是为宏睁开(宏替换)。
宏可以只有宏名,没有宏内容。
在C++中,内联函数可代替有参数的宏,效果更好。
C++中常用的宏:
- 当前源代码文件名:
- 当前源代码函数名:
- 当前源代码行号:
- 编译的日期:
- 编译的时间:
- 编译的时间戳:
- 当用C++编译程序时,宏__cplusplus就会被定义。
3)条件编译
满足条件才会编译
最常用的两种:#ifdef、#ifndef if #define if not #define
- #ifdef 宏名
- 程序段一
- #else
- 程序段二
- #endif
复制代码 含义:如果#ifdef背面的宏名已存在,则利用程序段一,否则利用程序段二。
4)办理头文件中代码重复包含的问题
在C/C++中,在利用预编译指令#include的时间,为了防止头文件被重复包含,有两种方式。
第一种:用#ifndef指令。
- #ifndef _GIRL_
- #define _GIRL_
- //代码内容。
- #endif
复制代码 第二种:把#pragma once指令放在文件的开头。
#ifndef方式受C/C++语言标准的支持,不受编译器的任何限制;而#pragma once方式有些编译器不支持。
#ifndef可以针对文件中的部分代码;而#pragma once只能针对整个文件。
#ifndef更加灵活,兼容性好;#pragma once操作简单,服从高。
二、编译和链接
1、源代码的组织
头文件(*.h):#include头文件、函数的声明、布局体的声明、类的声明、模板的声明、内联函数、#define和const定义的常量等。
源文件(*.cpp):函数的定义、类的定义、模板具体化的定义。
主程序(main函数所在的程序):主程序负责实现框架和核心流程,把需要用到的头文件用#include包含进来。
2、编译预处理
预处理的包罗以下方面:
1)处理#include头文件包含指令。
2)处理#ifdef #else #endif、#ifndef #else #endif条件编译指令。
3)处理#define宏定义。
4)为代码添加行号、文件名和函数名。
5)删除注释。
6)保留部分#pragma编译指令(编译的时间会用到)。
3、编译
将预处理天生的文件,颠末词法分析、语法分析、语义分析以及优化和汇编后,编译成若干个目的文件(二进制文件)。
4、链接
将编译后的目的文件,以及它们所需要的库文件链接在一起,形成一个体整。
5、更多细节
1)分开编译的利益:每次只编译修改过的源文件,然后再链接,服从最高。
2)编译单个*.cpp文件的时间,必须要让编译器知道名称的存在,否则会出现找不到标识符的错误。(直接和间接包含头文件都可以)
3)编译单个*.cpp文件的时间,编译器只需要知道名称的存在,不会把它们的定义一起编译。
4)如果函数和类的定义不存在,编译不会报错,但链接会出现无法剖析的外部命令。(C++编译的时间,只检查名称是否正当,u检查名称的定义即实体是否存在,链接的时间才会探求名称的定义,如果找不到就报错了)
5)链接的时间,变量、函数和类的定义只能有一个,否则会出现重定义的错误。(如果把变量、函数和类的定义放在.h文件中,.h会被多次包含,链接前可能存在多个副本;如果放在.cpp文件中,.cpp文件不会被包含,只会被编译一次,链接前只存在一个版本)
6)把变量、函数和类的定义放在.h中是不规范的做法,如果.h被多个*.cpp包含,会出现重定义。
7)用#include包含*.cpp也是不规范的做法,原理同上。
8)尽可能不利用全局变量,如果肯定要用,要在.h文件中声明(需要加extern关键字),在.cpp文件中定义。
9)全局的const常量在头文件中定义(const常量仅在单个文件内有效)。
10).h文件重复包含的处理方法只对单个的.cpp文件有效,不是整个项目。
11)函数模板和类模板的声明和定义可以分开誊写,但它们的定义并不是真实的定义,只能放在.h文件中;函数模板和类模板的具体化版本的代码是真实的定义,以是放在.cpp文件中。
12)Linux下C++编译和链接的原理与VS一样。
三、命名空间
在现实开发中,较大型的项目会利用大量的全局名字,如类、函数、模板、变量等,很轻易出现名字辩论的情况。
命名空间分割了全局空间,每个命名空间是一个作用域,防止名字辩论。
1、语法
创建命名空间:
- namespace 命名空间的名字
- {
- // 类、函数、模板、变量的声明和定义。
- }
复制代码 创建命名空间的别名:
namespace 别名=原名;
2、利用命名空间
在同一命名空间内的名字可以直接访问,该命名空间之外的代码则必须明白指出命名空间。
1)运算符::
语法:命名空间::名字
简单明了,且不会造成任何辩论,但利用起来比力繁琐。
2)using声明
语法:using 命名空间::名字
用using声明名后,就可以举行直接利用名称。
如果该声明区域有雷同的名字,则会报错。
3)using编译指令
语法:using namespace命名空间
using编译指令将使整个命名空间中的名字可用。如果声明区域有雷同的名字,局部版本将隐蔽命名空间中的名字,不过,可以利用域名剖析符利用命名空间中的名称。
3、注意事项
1)命名空间是全局的,可以分布在多个文件中。
2)命名空间可以嵌套。
3)在命名空间中声明全局变量,源文件中定义,头文件中声明;而不是利用外部全局变量和静态变量。
4)对于using声明,首选将其作用域设置为局部而不是全局。
5)不要在头文件中利用using编译指令,如果非要利用,应将它放在全部的#include之后。
6)匿名的命名空间,从创建的位置到文件结束有效。
四、C++类型转换-static_cast
C风格的类型转换很轻易明白:
语法:(目的类型)表达式或目的类型(表达式);
C++以为C风格的类型转换过于疏松,可能会带来隐患,不够安全。
C++推出了新的类型转换来替换C风格的类型转换,采用更严格的语法检查,降低利用风险。
C++新增了四个关键字static_cast、const_cast、reinterpret_cast和dynamic_cast,用于支持C++风格的类型转换。
C++的类型转换只是语法上的表明,本质上与C风格的类型转换没什么不同,C语言做不到事情的C++也做不到。
语法:
- static_cast<目标类型>(表达式); //用最多
- const_cast<目标类型>(表达式);
- reinterpret_cast<目标类型>(表达式);
- dynamic_cast<目标类型>(表达式);
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |