This commit is contained in:
许大仙 2024-08-26 11:17:32 +08:00
parent 5a8618ed70
commit 313cf9feba

View File

@ -597,11 +597,11 @@ int main() {
### 1.3.1 概述 ### 1.3.1 概述
* 在生活中,如果一个容器的容量是固定的,我们不停的向其中注入水,那么当容器中充满水之后,继续注入,就会溢出,如下所示: * 在生活中,如果一个容器的容量是固定的,我们不停的向其中注入水,那么当容器中充满水之后,继续注入,就会从杯子中溢出,如下所示:
![](./assets/3.jpg) ![](./assets/3.jpg)
* 在程序中也是一样的各种整数类型在内存中占用的存储单元是不同的short 在内存中占用 2 个字节的存储单元int 在内存中占用 4 个字节的存储单元。这也就意味着,各种整数类型只能存储有限的数值,当数值过大或多小的时候,超出的部分就会被直接截掉,那么数值就不能正确的存储,我们就将这种现象就称为`溢出`overflow * 在程序中也是一样的各种整数类型在内存中占用的存储单元是不同的short 在内存中占用 2 个字节的存储单元int 在内存中占用 4 个字节的存储单元。这也就意味着,各种整数类型只能存储有限的数值,当数值过大或多小的时候,超出的部分就会被直接截掉,那么数值就不能正确的存储,我们就将这种现象就称为`溢出`overflow
> [!NOTE] > [!NOTE]
> >
@ -611,7 +611,7 @@ int main() {
> [!IMPORTANT] > [!IMPORTANT]
> >
> * ① 在 C 语言中,程序产生数值溢出的时候,并不会引发错误而使程序自动停止,是因为计算机底层直接按照二进制补码的运算规则进行处理的很多编程语言也是这样处理的Java 等)。 > * ① 在 C 语言中,程序产生数值溢出的时候,并不会引发错误而使程序自动停止,这是因为计算机底层是采用二进制补码的运算规则进行处理的很多编程语言也是这样处理的Java 等)。
> * ② 但是这可能会导致不可预料的后果1996 年的亚利安 5 号运载火箭爆炸、2004 年的 Comair 航空公司航班停飞事故。 > * ② 但是这可能会导致不可预料的后果1996 年的亚利安 5 号运载火箭爆炸、2004 年的 Comair 航空公司航班停飞事故。
> * ③ 在实际开发中,编程时要特别注意,以避免数值溢出问题,特别是在涉及大数或小数的运算(特指整数)。 > * ③ 在实际开发中,编程时要特别注意,以避免数值溢出问题,特别是在涉及大数或小数的运算(特指整数)。
@ -1349,7 +1349,8 @@ int main() {
#include <stdio.h> #include <stdio.h>
/** /**
* 不同的整数类型混合运算时,宽度较小的类型会提升为宽度较大的类型,比如 short 转为 int int 转为 long 等。 * 不同的整数类型混合运算时,宽度较小的类型会提升为宽度较大的类型。
* 比如 short 转为 int int 转为 long 等。
*/ */
int main() { int main() {
@ -1357,7 +1358,8 @@ int main() {
int i = 20; int i = 20;
// s1 是 short 类型i 是 int 类型,当 s1 和 i 运算的时候,会自动转为 int 类型后,然后再计算。 // s1 是 short 类型i 是 int 类型。
// 当 s1 和 i 运算的时候,会自动转为 int 类型后,然后再计算。
int result = s1 + i; int result = s1 + i;
printf("result = %d \n", result); printf("result = %d \n", result);
@ -1379,7 +1381,8 @@ int main() {
int n2 = -100; int n2 = -100;
unsigned int n3 = 20; unsigned int n3 = 20;
// n2 是有符号n3 是无符号,当 n2 和 n3 运算的时候,会自动转为无符号类型后,然后再计算。 // n2 是有符号n3 是无符号。
// 当 n2 和 n3 运算的时候,会自动转为无符号类型后,然后再计算。
int result = n2 + n3; int result = n2 + n3;
printf("result = %d \n", result); printf("result = %d \n", result);
@ -1396,14 +1399,16 @@ int main() {
#include <stdio.h> #include <stdio.h>
/** /**
* 不同的浮点数类型混合运算时,宽度较小的类型转为宽度较大的类型,比如 float 转为 double double 转为 long double 。 * 不同的浮点数类型混合运算时,宽度较小的类型转为宽度较大的类型。
* 比如 float 转为 double double 转为 long double 。
*/ */
int main() { int main() {
float f1 = 1.25f; float f1 = 1.25f;
double d2 = 4.58667435; double d2 = 4.58667435;
// f1 是 float 类型d2 是 double 类型,当 f1 和 d2 运算的时候,会自动转为 double 类型后,然后再计算。 // f1 是 float 类型d2 是 double 类型。
// 当 f1 和 d2 运算的时候,会自动转为 double 类型后,然后再计算。
double result = f1 + d2; double result = f1 + d2;
printf("result = %.8lf \n", result); printf("result = %.8lf \n", result);
@ -1427,7 +1432,8 @@ int main() {
int n4 = 10; int n4 = 10;
double d3 = 1.67; double d3 = 1.67;
// n4 是 int 类型d3 是 double 类型,当 n4 和 d3 运算的时候,会自动转为 double 类型后,然后再计算。 // n4 是 int 类型d3 是 double 类型。
// 当 n4 和 d3 运算的时候,会自动转为 double 类型后,然后再计算。
double result = n4 + d3; double result = n4 + d3;
printf("%.2lf", result); printf("%.2lf", result);
@ -1470,7 +1476,7 @@ int main() {
} }
``` ```
### 1.6.3 强制类型转换 ### 1.7.3 强制类型转换
* 隐式类型转换中的宽类型赋值给窄类型,编译器是会产生警告的,提示程序存在潜在的隐患,如果非常明确地希望转换数据类型,就需要用到强制(或显式)类型转换。 * 隐式类型转换中的宽类型赋值给窄类型,编译器是会产生警告的,提示程序存在潜在的隐患,如果非常明确地希望转换数据类型,就需要用到强制(或显式)类型转换。
* 语法: * 语法:
@ -1479,7 +1485,7 @@ int main() {
数据类型 变量名 = (类型名)变量、常量或表达式; 数据类型 变量名 = (类型名)变量、常量或表达式;
``` ```
> [!CAUTION] > [!WARNING]
> >
> 强制类型转换可能会导致精度损失!!! > 强制类型转换可能会导致精度损失!!!
@ -1513,7 +1519,9 @@ int main(){
> [!NOTE] > [!NOTE]
> >
> 这些存储单元中,存储的都是 0 和 1 这样的数据,因为计算机只能识别二进制数。 > * ① 操作系统其实并不会直接操作实际的内存而是会通过内存管理单元MMU来操作内存并通过虚拟地址映射Virtual Address Mapping将程序使用的虚拟地址转换为物理地址。虚拟地址映射可以实现内存保护、内存共享和虚拟内存等功能使得程序能够使用比实际物理内存更大的内存空间同时确保程序间不会相互干扰。
> * ② 为了方便初学者学习,后文一律会描述 CPU 直接操作内存(这种说法不严谨,但足够简单和方便理解)。
> * ③ 这些存储单元中,存储的都是 0 和 1 这样的数据,因为计算机只能识别二进制数。
![](./assets/17.svg) ![](./assets/17.svg)