本帖最后由 jackz007 于 2022-10-18 19:12 编辑
原因终于被我找到了,看看两个可执行代码的 main() 函数反汇编
【有打印地址版本】:00401350 /$ 55 push ebp
00401351 |. 89E5 mov ebp, esp
00401353 |. 83E4 F0 and esp, FFFFFFF0
00401356 |. 83EC 20 sub esp, 20
00401359 |. E8 22060000 call 00401980
0040135E |. C64424 1B 00 mov byte ptr [esp+1B], 0 ; char a = 0
00401363 |? C64424 1A 00 mov byte ptr [esp+1A], 0 ; char b = 0
00401368 |? 8D4424 1A lea eax, dword ptr [esp+1A] ; eax = & b
0040136C |? 894424 1C mov dword ptr [esp+1C], eax ; p = & b
00401370 |? 8B4424 1C mov eax, dword ptr [esp+1C] ; eax = & b
00401374 |? C700 02010000 mov dword ptr [eax], 102 ; * p = 258
0040137A |. 0FB64424 1A movzx eax, byte ptr [esp+1A] ; eax = a
0040137F |? 0FBED0 movsx edx, al ; edx = a
00401382 |? 0FB64424 1B movzx eax, byte ptr [esp+1B] ; eax = b
00401387 |? 0FBEC0 movsx eax, al ; eax = b
0040138A |? 895424 08 mov dword ptr [esp+8], edx ; edx = b = 2 进堆栈 - 准备打印
0040138E |? 894424 04 mov dword ptr [esp+4], eax ; eax = a = 1 进堆栈 - 准备打印
00401392 |? C70424 24304000 mov dword ptr [esp], 00403024 ; ASCII "%d %d"
00401399 ? E8 52080000 call <jmp.&msvcrt.printf> ; 调用 printf()
0040139E . 8D4424 1A lea eax, dword ptr [esp+1A]
004013A2 ? 894424 08 mov dword ptr [esp+8], eax
004013A6 ? 8D4424 1B lea eax, dword ptr [esp+1B]
004013AA ? 894424 04 mov dword ptr [esp+4], eax
004013AE . C70424 2B304000 mov dword ptr [esp], 0040302B ; ASCII "%p %p"
004013B5 . E8 36080000 call <jmp.&msvcrt.printf>
004013BA ? B8 00000000 mov eax, 0
004013BF ? C9 leave
004013C0 > C3 retn
【无打印地址版本】:00401350 /$ 55 push ebp
00401351 |. 89E5 mov ebp, esp
00401353 |. 83E4 F0 and esp, FFFFFFF0
00401356 |. 83EC 20 sub esp, 20
00401359 |. E8 02060000 call 00401960
0040135E |. C64424 1F 00 mov byte ptr [esp+1F], 0 ; char a = 0
00401363 |. C64424 17 00 mov byte ptr [esp+17], 0 ; char b = 0
00401368 |. 8D4424 17 lea eax, dword ptr [esp+17] ; eax = & b
0040136C |. 894424 18 mov dword ptr [esp+18], eax ; p = & b
00401370 |. 8B4424 18 mov eax, dword ptr [esp+18] ; eax = & b
00401374 |. C700 02010000 mov dword ptr [eax], 102 ; * p = 258
0040137A |. 0FB64424 17 movzx eax, byte ptr [esp+17] ; eax = b
0040137F |. 0FBED0 movsx edx, al ; edx = b
00401382 |. 0FBE4424 1F movsx eax, byte ptr [esp+1F] ; eax = a
00401387 |. 895424 08 mov dword ptr [esp+8], edx ; b 进堆栈 - 准备调用 printf()
0040138B |. 894424 04 mov dword ptr [esp+4], eax ; a 进堆栈 - 准备调用 printf()
0040138F |. C70424 24304000 mov dword ptr [esp], 00403024 ; |ASCII "%d %d"
00401396 |. E8 35080000 call <jmp.&msvcrt.printf> ; \printf
0040139B |. B8 00000000 mov eax, 0
004013A0 |. C9 leave
004013A1 \. C3 retn
主要聚焦下面的不同点:
【有打印地址版本】:0040135E |. C64424 1B 00 mov byte ptr [esp+1B], 0 ; char a = 0
00401363 |? C64424 1A 00 mov byte ptr [esp+1A], 0 ; char b = 0
【无打印地址版本】:0040135E |. C64424 1F 00 mov byte ptr [esp+1F], 0 ; char a = 0
00401363 |. C64424 17 00 mov byte ptr [esp+17], 0 ; char b = 0
有打印地址版本的 a、b 内存地址符合预期,b 在前,a 在后,存储地址相差 1 个字节;无打印地址版本 a、b 内存地址不符合预期,虽然 b 在前,a 在后,符合预期,但是,存储地址却相差了 8 个字节,这样,当 * p = 258 覆盖内存的时候,只能覆盖 b,根本不法覆盖到 a,所以,打印 a、b 的时候,b 是覆盖后的值,a 是原始值,所以,就看到了 2 和 0。
之所以有这种不同的结果,应该和编译器对局部变量的内存分配策略有关,我使用 gcc,和楼主在 Linux 系统下所使用的编译器同源,所以,可以重现楼主在 Linux 系统下看到的相同情况。
基于以上分析结论,只要把 a、b 为 2 个 char 型变量的定义改为一个 2 元素 char 型数组即可完美解决问题#include <stdio.h>
int main(void)
{
char b[2] = {0} ;
int * p = (int *) b ;
* p = 258 ;
printf("%d %d\n" , b[0] , b[1]) ;
// printf("%p %p\n" , & a , & b) ;
}
楼主不妨一试
|