指针的赋值过程与指针类型的真相 int指针: int gi; int *p; p = &gi; 00EF166E C7 05 3C 91 EF 00 38 91 EF 00 mov dword ptr ds:[00EF913Ch],0EF9138h
*p = 12; 00EF1678 A1 3C 91 EF 00 mov eax,dword ptr ds:[00EF913Ch] 00EF167D C7 00 0C 00 00 00 mov dword ptr [eax],0Ch
注释: p = &gi; mov dword ptr ds:[00EF913Ch],0EF9138h 将gi的地址0EF9138h放入00EF913Ch所指向的地址中保存 *p = 12; mov eax,dword ptr ds:[00EF913Ch ] 将00EF913Ch所存储的地址,也就是gi的地址0EF9138h放入eax中. mov dword ptr [eax],0Ch 将0ch放入eax所存储的地址中,也就是把0ch放在了gi所代表的地址中,dword也就代表了向eax中写入4字节数据
short型指针:
short gi; short *p; p = &gi; 0034166E C7 05 3C 91 34 00 38 91 34 00 mov dword ptr ds:[0034913Ch],349138h *p = 12; 00341678 B8 0C 00 00 00 mov eax,0Ch 0034167D 8B 0D 3C 91 34 00 mov ecx,dword ptr ds:[0034913Ch] 00341683 66 89 01 mov word ptr [ecx],ax 注释: mov dword ptr ds:[0034913Ch],349138h 将gi的地址0EF9138h放入00EF913Ch所指向的地址中保存 *p = 12; mov eax,0Ch 将0Ch放入eax中,由于eax是4字节,所以0ch放到了eax的低2字节,ax中 mov ecx,dword ptr ds:[0034913Ch] 将p所存储的地址,也就是gi的地址放入ecx中. mov word ptr [ecx],ax 将ax所存储的内容写入到ecx所指向的地址,也就是gi的地址,.word说明将向gi的地址写入2字节数据
char型指针: char *p; p = &gi; 00CC166E C7 05 3C 91 CC 00 38 91 CC 00 mov dword ptr ds:[00CC913Ch],0CC9138h *p = 12; 00CC1678 A1 3C 91 CC 00 mov eax,dword ptr ds:[00CC913Ch] 00CC167D C6 00 0C mov byte ptr [eax],0Ch
注释: mov dword ptr ds:[00CC913Ch],0CC9138h 将gi的地址0EF9138h放入00EF913Ch所指向的地址中保存
*p = 12; mov eax,dword ptr ds:[00CC913Ch] 将00EF913Ch所存储的地址,也就是gi的地址0EF9138h放入eax中. mov byte ptr [eax],0Ch 将0ch放入eax所存储的地址中,也就是把0ch放在了gi所代表的地址中,byte 也就代表了向eax所存储的地址中写入1字节数据
总结: C语言指针包含两方面信息,一个是地址,存放在指针变量中,另一个是类型信息,决定了读写的长度,没有存储在指针变量中,位于指针读写过程所使用的mov指令中,不同的指针类型对应着读写的字节数. 这也间接解释了指针为什么+-1不是+-1个字节,而是加减长度是指针类型的字节数,void类型的指针之所以无法加减,就是因为它没有类型信息,无法确定加减的长度,代表的仅仅是一块内存地址.
指针类型强制转换 /****************************************************************/ 程序: int i; int * pi; short * ps; char * pc; int main() { pi = &i; ps = ( short *)&i; pc = ( char *)&i; *pi = 0x1234; *ps = 0x1234; *pc = 0x12; } /***************************************************************/
反汇编:
pi = &i; 00941A8E C7 05 E0 94 94 00 DC 94 94 00 mov dword ptr ds:[009494E0h],9494DCh ps = (short *)&i; 00941A98 C7 05 E4 94 94 00 DC 94 94 00 mov dword ptr ds:[009494E4h],9494DCh pc = (char *)&i; 00941AA2 C7 05 E8 94 94 00 DC 94 94 00 mov dword ptr ds:[009494E8h],9494DCh *pi = 0x1234;
注释: 在把i赋值其他指针变量的过程中,强制转换并没有生成任何指令,可见,强制转换并不是在这里产生效果的
00941AAC A1 E0 94 94 00 mov eax,dword ptr ds:[009494E0h] 00941AB1 C7 00 34 12 00 00 mov dword ptr [eax],1234h *ps = 0x1234; 00941AB7 B8 34 12 00 00 mov eax,1234h 00941ABC 8B 0D E4 94 94 00 mov ecx,dword ptr ds:[009494E4h] 00941AC2 66 89 01 mov word ptr [ecx],ax *pc = 0x12; 00941AC5 A1 E8 94 94 00 mov eax,dword ptr ds:[009494E8h] 00941ACA C6 00 12 mov byte ptr [eax],12h
注释: 可以看出,在这里,写入的字节数发生了变化,所以,强制转换的效果不在转换过程中体现,而是体现在转换后去访问内存时的指令中
注释2: 如果转换后指针指向的数据类型大小小于原来的数据类型大小,那么用该转换后的指针访问就不会越过原数据的内存,是安全的,否则危险,要越界
/*****************************************************/ 程序: #include<stdio.h>
int main() { int * pi; short si = 12; pi = ( int *)&si; printf( "%d,%x", *pi, *pi); } /*****************************************************/
注释: 正常情况下这段程序应该输入的是12,0c 但是实际上的运行结果是-859045876,cccc000c 这是由于将si的地址强制转换为int *类型,然后赋值给pi;那么pi会访问4字节,这时越界了,将si后的2字节纳入了范围,即是cc cc,他们和0c 00合在一起正好与结果吻合 这就是违反了强制转换的原则,越界了
|