整数和浮点数在内存的存储

深入解析:大小端、整型与浮点数在内存中的存储原理,

目录

1.大小端

2.整型在内存的存储

3.浮点型在内存的存储


 

1.大小端

int main()
{
	int a = 0x11223344;
	return 0;
}

我们看出一个问题,为什么a按字节为单位,它的数据是倒着存储的呢? 

1.1什么是大小端?

字节在超过数据存储的时候就会有存储顺序的问题,在不同的存储顺序,我们分为大端存储和小端存储。

大端存储:低位字节数据存储在高地址处,高位字节数据存储在低地址处。

小端存储:低位字节数据存储在低地址处,高位字节数据存储在高地址处。

1.2为什么要分大小端

因为寄存器宽度⼤ 于⼀个字节,就会存在着⼀个如何将多个字节安排的问题。因此就导致了⼤端存储模式和⼩端存储模式。

2.整型在内存的存储

整型在内存的存放模式就是二进制的补码来进行存储的 

在计算机系统中,数值⽤补码来表⽰和存储。 原因在于,使⽤补码,可以将符号位和数值域统处理; 同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是 相同的,不需要额外的硬件电路。

3.浮点型在内存的存储

int main()
{
	int n = 7;
	float* pf = (float*)&n;
	printf("n的值为:%d\n", n);
	printf("*pf的值为:%f\n", *pf);
	*pf = 7.0;
	printf("n的值为:%d\n", n);
	printf("*pf的值为:%f\n", *pf);
	return 0;
}

我们可以看出为什么输出没有正确的打出对应的数值

浮点数在计算机内部的表⽰⽅法是根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:

V   =  (−1) 的s次方∗ M ∗ 2的E次方
(−1) S 表⽰符号位,当S=0,V为正数;当S=1,V为负数
M 表⽰有效数字,M是⼤于等于1,⼩于2的
E 表⽰指数位
举例来说:
⼗进制的5.0,写成⼆进制是 101.0 ,相当于 1.01×2^2
那么,按照上⾯V的格式,可以得出S=0,M=1.01,E=2。
⼗进制的-5.0,写成⼆进制是 -101.0 ,相当于 -1.01×2^2 。那么,S=1,M=1.01,E=2。
规定:
对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M

对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M


这就是所有内容啦,如有错误批评指正,谢谢。 

<think>我们已知用户想要通过gdb查看整数浮点数内存中的存放形式。根据之前的引用,我们知道gdb可以通过x命令查看内存,并且可以指定显示的格式。 整数浮点数内存中的存储方式不同:整数一般用补码,浮点数用IEEE 754标准。我们可以通过gdb的x命令以十六进制字节形式查看内存,从而观察其存储形式。 步骤: 1. 编写一个简单的C程序,包含整数浮点数变量。 2. 使用gdb调试程序,在变量赋值后设置断点。 3. 使用gdb的x命令(examine memory)查看变量的内存表示。 示例程序(test.c): ```c #include <stdio.h> int main() { int i = 0x12345678; float f = -6.25f; return 0; // 设置断点在这里 } ``` 编译程序时需要加上-g选项以包含调试信息: gcc -g -o test test.c 使用gdb调试: gdb ./test 在gdb中: (gdb) break main.c:5 // 在return 0处设置断点 (gdb) run // 运行程序到断点 (gdb) print &i // 获取变量i的地址,假设输出为0x7fffffffde24 (gdb) print &f // 获取变量f的地址 然后使用x命令查看内存: (gdb) x/4xb &i // 查看整数i的4个字节(以十六进制字节形式) (gdb) x/4xb &f // 查看浮点数f的4个字节 注意:由于系统可能是小端序,整数0x12345678在内存中会按照从低地址到高地址为0x78, 0x56, 0x34, 0x12。 浮点数-6.25的IEEE 754单精度表示为0xC0C80000(二进制:11000000110010000000000000000000),小端序存储则为00 00 C8 C0。 另外,引用[5]给出了使用x命令查看内存的例子:`x/16xb 0x7FFFFFFFE0F8`,表示从地址0x7FFFFFFFE0F8开始显示16个字节,十六进制字节格式。 因此,我们可以这样操作: 对于整数i(假设地址为addr_i): (gdb) x/4xb addr_i // 查看4个字节,十六进制格式 对于浮点数f(假设地址为addr_f): (gdb) x/4xb addr_f // 同样查看4个字节 如果想同时看到变量值,可以在gdb中使用print命令打印变量值,但注意print会按照变量类型解释内存,而x命令直接查看原始内存。 此外,我们还可以利用gdb的数据显示格式(如引用[1]提到)来以不同格式输出同一个变量。例如,我们可以用二进制格式查看整数: (gdb) print/t i // 以二进制形式输出整数i 但注意,直接查看内存更直接反映存储形式。 下面给出详细步骤: 步骤1:编写C程序(test.c) 步骤2:编译:gcc -g test.c -o test 步骤3:启动gdb:gdb ./test 步骤4:在main函数中return 0处设置断点:break test.c:5(具体行号根据程序) 步骤5:运行:run 步骤6:当程序停在断点处时,使用以下命令: p &i // 打印i的地址,记下地址,比如0x7fffffffde24 p &f // 打印f的地址,记下地址,比如0x7fffffffde20 步骤7:查看整数i的内存: x/4xb 0x7fffffffde24 // 注意替换为实际地址 预期输出(小端序):0x78, 0x56, 0x34, 0x12 步骤8:查看浮点数f的内存: x/4xb 0x7fffffffde20 // 注意替换为实际地址 预期输出(小端序):0x00, 0x00, 0xc8, 0xc0 步骤9:也可以使用其他格式查看,比如查看整数的十六进制值: p/x i // 以十六进制输出i的值,应该为0x12345678 步骤10:查看浮点数的十六进制表示(IEEE 754): p/f f // 输出浮点数值,为-6.25 p/x *(int *)&f // 将浮点数地址强制转换为整数指针,然后取整数值(即内存中的位模式),输出应为0xc0c80000(注意,这里显示的是整数形式的十六进制,但内存字节顺序是小端,所以在内存存储为00 00 c8 c0,但转换为整数时是按小端序组合的,所以整数显示为0xc0c80000?实际上这里有一个转换:小端序下,如果我们按字节从低到高是00,00,c8,c0,那么组合成32位整数就是0xc0c80000(因为低地址是低位,高地址是高位)?不对,组合后应该是0xC0C80000,但注意在x86上,当我们把这四个字节当作一个32位整数时,它的值就是0xC0C80000?不对,比如我们存储的四个字节是:地址A:00, A+1:00, A+2:C8, A+3:C0,那么32位整数就是0xC0C80000(因为高字节在高地址,低字节在低地址,所以整数是0xC0C80000)。但是,我们使用x/4xb看到的是从低地址到高地址的字节序列:00 00 C8 C0,所以当我们用整数解释时,这个值就是0xC0C80000(因为C0在最高地址,作为最高字节)。所以用p/x *(int*)&f会显示0xC0C80000。 实际上,上面的步骤10可以这样验证浮点数内存表示,但注意类型转换可能在不同编译器下有差异。 因此,总结查看内存存放形式的方法: 对于整数:直接使用x命令查看其地址处的字节,或者使用print以十六进制输出整数值(但注意print输出的整数值是经过转换的,而内存字节顺序需要单独考虑)。 对于浮点数:同样使用x命令查看字节,或者使用强制类型转换将其内存解释为整数后再输出(这样可以看到整个位模式)。 注意:由于gdb的x命令默认显示的是字节序列(小端序),所以我们看到的是内存中的实际排列。而如果使用print打印整数值(强制转换后的),则直接得到的是该地址处按小端序组合的整数。 因此,我们可以提供两种方法: 方法一:使用x命令直接查看内存字节(推荐,因为最直接)。 方法二:使用强制类型转换后打印整数形式(这样可以看到整个位模式的十六进制值)。 下面按照要求组织回答: </think>### 使用 GDB 查看整数浮点数内存存放形式的方法 #### 📌 核心步骤概览 1. **编译调试版本程序**:使用 `gcc -g` 编译包含整数浮点变量的代码 2. **启动 GDB 调试**:加载可执行文件并设置断点 3. **查看内存地址**:获取目标变量的内存地址 4. **使用 `x` 命令解析内存**:按字节查看原始内存数据 5. **结合数据格式解析**:根据类型解释内存内容 --- ### 🔍 详细操作指南 #### 步骤 1:准备测试代码 ```c #include <stdio.h> int main() { int num = 0x12345678; // 整型常数示例(十六进制) float f = -6.25f; // 浮点常数示例 return 0; // 在此设断点 } ``` 编译时添加调试信息: ```bash gcc -g -o mem_test mem_test.c ``` --- #### 步骤 2:启动 GDB 调试 ```bash gdb ./mem_test (gdb) break 6 # 在return语句设断点[^4] (gdb) run ``` --- #### 步骤 3:获取变量地址 ```bash (gdb) print &num $1 = (int *) 0x7fffffffde24 # 记录整型地址 (gdb) print &f $2 = (float *) 0x7fffffffde20 # 记录浮点地址 ``` --- #### 步骤 4:查看整型内存布局 使用 `x/4xb` 命令查看 4 字节内存(十六进制字节格式): ```bash (gdb) x/4xb 0x7fffffffde24 0x7fffffffde24: 0x78 0x56 0x34 0x12 ``` 🔎 解析: - 小端序存储(低位在前):`78 56 34 12` → 实际值 `0x12345678` - 内存布局验证: | 地址偏移 | 值 | 含义 | |----------|--------|----------------| | +0 | `0x78` | 最低有效字节 | | +1 | `0x56` | | | +2 | `0x34` | | | +3 | `0x12` | 最高有效字节 | --- #### 步骤 5:查看浮点内存布局 ```bash (gdb) x/4xb 0x7fffffffde20 0x7fffffffde20: 0x00 0x00 0xc8 0xc0 ``` 🔎 解析(IEEE 754 单精度): 1. **原始字节**:`00 00 c8 c0`(小端序)→ 实际存储 `0xC0C80000` 2. **二进制拆分**: ```binary 1 10000001 10010000000000000000000 ┬ ──────── ─────────────────────── │ │ │ │ │ └─ 尾数段 (23bit): 0.1001 │ └─ 指数段 (8bit): 129 - 127 = 2 └─ 符号位 (1bit): 1(负数) ``` 3. **值计算**: $$ \begin{align*} \text{值} &= (-1)^1 \times (1 + 2^{-1}) \times 2^2 \\ &= -1 \times 1.5 \times 4 \\ &= -6.0 \quad \text{❌ 需修正} \end{align*} $$ ✅ 正确解析:尾数实际为 $1.1001_2 = 1 + 0.5 + 0.0625 = 1.5625$ $$ -1 \times 1.5625 \times 4 = -6.25 $$ --- #### 💡 高级技巧:直接查看位模式 ```bash (gdb) print/x *(int*)&f # 将float内存解释为整数[^2] $3 = 0xc0c80000 (gdb) print/t *(int*)&f # 二进制格式输出[^1] $4 = 110000001100100000000000000000 ``` --- ### 📊 关键命令总结 | 目的 | GDB 命令 | 输出示例 | |-------------------------|--------------------------------|------------------------------| | 查看整型内存 | `x/4xb <int_address>` | `0x78 0x56 0x34 0x12` | | 查看浮点内存 | `x/4xb <float_address>` | `0x00 0x00 0xc8 0xc0` | | 浮点位模式(十六进制) | `print/x *(int*)&<float_var>` | `0xc0c80000` | | 浮点位模式(二进制) | `print/t *(int*)&<float_var>` | `1100000011001000...` | > ⚠️ **注意事项** > 1. 字节顺序取决于 CPU 架构(x86/x64 为小端序) > 2. 浮点解析需严格遵循 IEEE 754 标准[^2] > 3. 指针转换仅用于查看内存布局,勿用于实际计算
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值