C++ 基础(十)程序文件和预处理指令
2021/8/6 1:35:49
本文主要是介绍C++ 基础(十)程序文件和预处理指令,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1. 理解转换单元
- 头文件包含函数声明和类型定义,源文件创建额外的函数定义。
- 源文件所包含的头文件的内容称为一个转换单元。
- 编译器独立处理程序中每个转换单元来生成对象文件。
- 单一定义原则:
- 单一定义原则ODR是一个重要概念,程序中定义的每个实体类型对应一个规则。
- ODR思想:有助于更好理解如何多个文件中组织程序的代码。
- 转换单元中,变量,函数,类类型,枚举类型,模板都只能定义一次。不同代码块中,定义的变量可以由相同的名称。
- 整个程序内部,大部分函数和变量必须定义一次,且只能被定义一次。内联函数和变量定义需要在调用它们的每个转换单元出现一次,但它们的定义必须相同。
- 类和枚举类型通常出现在多个转换单元中,几个转换单元允许分别包含定义,定义必须相同。
- 函数模板,使用之前未见的模板实参实例化的单元中,包含模板定义。
- 文件和链接
- 转换单元中的名称在编译/链接过程中处理方式由链接属性确定。
- 链接属性指定了由一个名称表示的实体可以在程序的什么中使用。
- 每个名称,要么由链接属性,要么没有链接属性。某个名称由于在声明该名称的作用域外部访问程序时,有链接属性,否则没有链接属性。
- 确定名称的链接属性
- 内部链接属性:该名称表示的实体可以在同一个转换单元内任何地方访问。
- 外部链接属性:除了在定义它的转换单元中访问外,还可以在另一个转换单元访问。
- 没有链接属性:没有链接属性,该名称只能应用于改名称的作用域中访问。
- 外部函数:
- 函数没有在调用它的转换单元中定义,编译器会把这个调用标记为外部的,让链接程序处理。
- #include 一句指令,也会在转换单元中引入大量的代码。
- 外部变量:
- 在源文件中使用外部定义的变量,方法是在外部的cpp文件中定义变量,在使用时extern导入。
- int power_range {3}; // Range.cpp extern int power_range; // main.cpp
- extern声明中不能指定初始值,它是名称的声明,不是变量的定义。
- 函数定义前面也能加上extern,但这种做法是可选的。
- 具有外部链接属性的const变量
- const关键字默认情况下具有内部链接属性,这使它不能在其它转换单元中使用。定义中使用extern可以重写这个属性。
- 最好在头文件中定义常量。
- 在源文件中使用外部定义的变量,方法是在外部的cpp文件中定义变量,在使用时extern导入。
- 内部名称:
- 函数默认会有外部链接属性,当一个函数充当源文件中的辅助函数,应该具有内部链接属性而不是外部链接属性。
- 第一种方式是添加intern修饰符,或者为一个名称(变量名或者函数名)添加static关键字。
- 最为推荐的方式是使用未命名的名称空间。
2. 预处理源代码
- 所有预处理指令都由#号开头,以便与C++的语句区分开。
- 比较少见的几个预处理指令:
- #line 重新定义当前行号,也可以用来修改文件名。
- #error 输出编译错误,停止编译。
- #pragma 提供某计算机专用的特性,同时保证与C++整体兼容。
3. 定义预处理宏
- #define PI 3.1415926
- C++建议的做法:
- inline const double pi {3.1415926}; // 常量
- extern const double pi {3.1415926}; // 定义为具有外部的链接属性
- C++不使用#define指令定义标识符,这么做有三个缺点:不支持类型检查,没有考虑作用域,标识符名称不能限定在名称空间中。
- C++中#define的作用主要是管理头文件。
- 定义类似于函数的宏:
- 宏函数看起来很像函数,但不是函数,没有实参,没有返回类型。
- 宏函数常见的缺陷:需要注意括号的使用;宏函数参数展开可能是函数,数值可能不是期望的值。
- C++的解决方案是函数模板。
- 预处理运算符:
- # 字符串化运算符,将实参转为包含其值的字符串字面量,用双引号包围实参,并添加必要的转义字符。
- ## 连接运算符,将两个标识符的值连接起来,类似于使用 + 将两个string对象的值连接起来。
- 取消宏定义:#undef
4. 包含头文件
- <> 和 " " 两种方式。
- 方式重复包含:
- #ifndef #define #endif
- #pragma once
5. 名称空间
- 使用名称空间避免命名冲突。
- 没有定义名称空间的代码都在全局名称空间中,在多个源文件中,具有链接属性的名称都在全局名称空间中。
- 定义名称空间:namespace myRegin {}
- 名称空间不能包含 main()
- 同名的名称空间会扩展名称空间的作用域。
- 名称空间若放在头文件中,#include保护符保证了这些定义不会在同一转换单元出现一次以上。但是不会阻止被包含到多个独立的转换单元,需要把成员都声明内联。这样就允许出现在多个转换单元中,不违反ODR。没有#include保护符时,也能使用extern代替inline。
- 应用using声明:using ns_name::identifier;
- 函数和名称空间:把函数原型放到名称空间中,定义时需要使用名称空间进行限定。
- 未命名的名称空间:
- 只使用了namespace关键字,没用命名。编译器为其生成内部的名称,一个转换单元内只能有一个未命名空间,其他命名空间都是第一个的扩展。
- 未命名空间不在全局名称空间,有内部链接属性,无外部链接属性。实际上是确保名称不在转换单元外部访问的一种方式,声明为static有相同的效果。
- 嵌套的名称空间:
- 使用时需要增加多个名称空间的名字进行限定。
- 名称空间的别名:namespace AA = ABC::A::a;
6. 逻辑预处理指令
- #ifdef #endif
- #if (不包含强制类型转换的整数常量表达式) #endif
- 代码选择:
- #if #else #endif
- #if #elif #else #endif
- 标准预处理宏:
- __LINE__ __FILE__ __DATE__ __TIME__ __cplusplus__
- 检查是否包含头文件:
- C++17中引入了__has_include()宏
- #if __has_include(<header>) #elif __has_include("Someheader.h") #else #endif
7. 调试方法
- 集成调试器
- C++编译器提供了内置的调试工具。
- 功能一般有:跟踪程序流,设置断点,设置观察窗口,检查程序元素。
- 预处理指令
- 使用#ifdef SWITCH #endif 设置代码开关。
- 随机数
- 先调用srand()传递一个无符号的整数种子值,调用rand()得到随机数序列。
- ctime中的time()返回秒数,作为随机数的一个参数。
- 使用assert()宏:(动态断言,运行时起作用)
- assert(expression);表达式是false,程序终止,调用std::abort(),显示标准错误流,cerr中的信息。
- 关闭assert()宏:程序开头定义#define NDEBUG 需要放在包含assert头文件中的#include之前才会有效。
8. 静态断言
- static_assert(constant_expression);
- static_assert(constant_expression, error_message)
- 参数一:编译期间可以转为bool的语句,false时,编译失败,输出参数二的message。
- 可以做参数一的语句:字面量,字面量初始化的const变量,宏,sizeof运算符,模板实参等。
- 常见用途是模板定义中验证模板参数:
- static_assert(std::is_arithmetic_v<T>);//判断T是否为算术类型。
这篇关于C++ 基础(十)程序文件和预处理指令的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-26怎么使用nsenter命令进入容器?-icode9专业技术文章分享
- 2024-12-26导入文件提示存在乱码,请确定使用的是UTF-8编码怎么解决?-icode9专业技术文章分享
- 2024-12-26csv文件怎么设置编码?-icode9专业技术文章分享
- 2024-12-25TypeScript基础知识详解
- 2024-12-25安卓NDK 是什么?-icode9专业技术文章分享
- 2024-12-25caddy 可以定义日志到 文件吗?-icode9专业技术文章分享
- 2024-12-25wordfence如何设置密码规则?-icode9专业技术文章分享
- 2024-12-25有哪些方法可以实现 DLL 文件路径的管理?-icode9专业技术文章分享
- 2024-12-25错误信息 "At least one element in the source array could not be cast down to the destination array-icode9专业技术文章分享
- 2024-12-25'flutter' 不是内部或外部命令,也不是可运行的程序 或批处理文件。错误信息提示什么意思?-icode9专业技术文章分享