目录
1. define和const的区别?
define 和 const 是在C和C++中用来定义常量的两种不同方式,它们有以下几点区别:
① 作用域和类型安全性;
② 调试和可读性;
③ 预处理处理时间;
④ 符号的作用范围。
1.1 作用域和类型安全性
define 宏:define 是预处理指令,它在编译之前就会被处理,并且没有作用域限制。define
定义的常量是简单的文本替换,不会进行类型检查和作用域检查。因此,它们的作用域是全局的,且不会保留类型信息。
#define PI 3.14159
const 常量:const 是C和C++中的关键字,用来定义常量并且具有类型。const
常量在编译时会进行类型检查,并且有作用域限制,因此更加安全和可靠。
const double PI = 3.14159;
1.2 调试和可读性
使用 const 定义的常量在编译器处理之后保留了类型信息,因此更容易调试和理解代码。而 define 定义的常量仅是简单的文本替换,不会展示出常量的实际值或类型。
1.3 预处理处理时间
define 是在预处理阶段处理的,它们在编译前被替换为常量值或表达式。而 const 常量是在编译阶段进行处理的,保留了编译时的类型检查和优化特性。
1.4 符号的作用范围
define 定义的符号在整个代码中都是可见和有效的,包括所有的源文件,而 const 常量则在定义它的作用域内有效,提供了更好的封装性。
使用 define
宏定义常量
#include <iostream>
using namespace std;
// 使用 #define 宏定义常量 PI
#define PI 3.14159
int main() {
double radius = 5.0;
double area = PI * radius * radius;
cout << "圆的面积为: " << area << endl;
// 尝试修改宏定义,编译器不会报错
#undef PI
#define PI 3.14
double new_area = PI * radius * radius;
cout << "新圆的面积为: " << new_area << endl;
return 0;
}
#define PI 3.14159:这行代码将 PI 定义为一个宏,其值为 3.14159。在编译预处理阶段,所有出现 PI 的地方都会被简单替换为 3.14159。
#undef PI 和 #define PI 3.14:这两行代码分别取消了之前的宏定义 PI
,然后重新定义为 3.14
。这种操作是在编译预处理阶段完成的,因此不会影响运行时的变量。
这种方法的好处是简单直接,并且可以用来定义简单的常量值。但是缺点是宏不会进行类型检查,也不会被编译器记录,因此在调试时不会显示出宏的具体值。
使用 const
常量定义常量
#include <iostream>
using namespace std;
int main() {
const double PI = 3.14159;
double radius = 5.0;
double area = PI * radius * radius;
cout << "圆的面积为: " << area << endl;
return 0;
}
const double PI = 3.14159;:这行代码使用 const 关键字定义了一个双精度浮点型常量 PI,其值为 3.14159,关键字 const 表示 PI 是一个只读变量,一旦初始化后,其值不能再被修改。在编译器处理时,const 常量会进行类型检查,并且有作用域限制,如上代码 PI 的作用域限制在main 函数内,这意味着它只能在 main 函数中使用,而在函数外部是不可见的。
const 常量提供了更好的类型安全性和可读性,因为它们在代码中保留了类型信息,也可以被编译器记录和优化。
简单来说:
#define 宏定义
优点:在编译器在处理时并不关心宏的具体值或类型,其可以在任何地方重新定义或者取消定义,对于简单的常量定义或者特定的预处理需求,#define 宏定义则是一种便捷有效的选择。
缺点:宏定义不会进行类型检查,也不会保留类型信息。这意味着在使用宏定义时,可能会出现意外的文本替换,导致错误或者难以调试的问题。
const
优点:具有类型,编译器会对其进行类型检查,确保在使用时符合类型规定,避免意外的类型错误。具有明确的作用域,仅在定义的块或文件内可见,不会像宏定义那样污染全局命名空间。
缺点:如果需要在预处理阶段(编译前)就替换为常量值,const 不适合,因为它不参与预处理阶段,而是在编译器进行类型检查和符号解析时生效。
2. IIC为什么要加上拉电阻,为什么使用开漏输出
2.1 上拉电阻
定义逻辑高电平:IIC总线上的设备是通过拉低(逻辑0)和不拉低(逻辑1)SDA和SCL线来通信的。上拉电阻确保当设备不主动拉低线时(即释放线),线路会被上拉到逻辑高电平(通常是Vcc或3.3V),从而保证了逻辑高的定义和通信的准确性。
信号线的回复位:IIC总线采用的是开漏输出,这意味着在逻辑0时设备可以拉低线路,而在逻辑1时,设备不对线路施加电平,而是释放线路。上拉电阻确保即使设备释放线路,线路上也会保持逻辑高电平,而不会漂浮。
简单来说,上拉电阻的作用是当IIC总线在空闲状态,使SDA和SCL处于高电平状态,并且使总线在处于开漏输出状态下时可以完成高低电平之间的转换。
2.2 开漏输出
开漏输出指的是设备在输出高电平时,其输出端口处于高阻抗状态(即不拉高),而在输出低电平时则拉低输出端口,这种输出的优势包括:
① 多主机系统兼容性:在I2C总线中,允许多个设备共享同一条总线。开漏输出使得多个设备可以以一种非干扰的方式共享总线,因为设备只需拉低线路来发送逻辑0,而不会直接推高电平。
② 容错能力:开漏输出增强了总线的容错能力。如果多个设备同时尝试拉低线路,总线会被拉到逻辑0。当设备释放线路时,上拉电阻确保线路上升到逻辑高电平。
③ 电平适配能力:允许设备以不同电平(例如3.3V或5V)进行通信,因为线路的逻辑高电平由上拉电阻确定,而不受单个设备的输出电平影响。
总结:根据其拉低不拉高的特性,可以通过不同的上拉电阻确定不同的逻辑高(高电平),并且设备不会主动拉高电平,只能释放总线,因此不会出现电平冲突的情况,提高了容错能力。