mirror of
https://github.com/Aexiar/c.git
synced 2024-10-22 12:05:45 +00:00
c
This commit is contained in:
parent
5a8618ed70
commit
313cf9feba
@ -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,8 +611,8 @@ int main() {
|
|||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
>
|
>
|
||||||
> * ① 在 C 语言中,程序产生数值溢出的时候,并不会引发错误而使程序自动停止,是因为计算机底层直接按照二进制补码的运算规则进行处理的(很多编程语言也是这样处理的,如:Java 等)。
|
> * ① 在 C 语言中,程序产生数值溢出的时候,并不会引发错误而使程序自动停止,这是因为计算机底层是采用二进制补码的运算规则进行处理的(很多编程语言也是这样处理的,如:Java 等)。
|
||||||
> * ② 但是,这可能会导致不可预料的后果,如:1996 年的亚利安5号运载火箭爆炸、2004 年的 Comair 航空公司航班停飞事故。
|
> * ② 但是,这可能会导致不可预料的后果,如:1996 年的亚利安 5 号运载火箭爆炸、2004 年的 Comair 航空公司航班停飞事故。
|
||||||
> * ③ 在实际开发中,编程时要特别注意,以避免数值溢出问题,特别是在涉及大数或小数的运算(特指整数)。
|
> * ③ 在实际开发中,编程时要特别注意,以避免数值溢出问题,特别是在涉及大数或小数的运算(特指整数)。
|
||||||
|
|
||||||
### 1.3.2 无符号数的取值范围
|
### 1.3.2 无符号数的取值范围
|
||||||
@ -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)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user