http://hi.baidu.com/abcdxyzk/item/80edd3026880bff7a0103492 同一個(gè)數(shù)可以通過不同的方式表達(dá)出來,對于函數(shù)的訪問,變量的賦值除了直接對變量賦值以外,還可以通過絕對內(nèi)存地址進(jìn)行參數(shù)賦值與函數(shù)調(diào)用。 (1) 通過地址修改變量的值 int x;int *p;printf("%x\n",&x); p=(int *)0x0012ff60; *p = 3; printf("%d\n",x); 程序的輸出結(jié)果為: 12ff603 程序首先輸出變量x所在地址為十六進(jìn)制的0x12ff60(本來應(yīng)該為8位的十六進(jìn)制數(shù),高位為0則省略掉),然后定義一個(gè)指針變量,讓它指向該地址,通過指針變量的值來修改變量x的值。 示例代碼: int *ptr=(int*)0xa4000000;*ptr=0xaabb; printf("%d\n",*ptr); 以上程序會(huì)崩潰,因?yàn)檫@樣做會(huì)給一個(gè)指針分配一個(gè)隨意的地址,很危險(xiǎn),所以這種做法是不允許的。 (2) 通過地址調(diào)用函數(shù)的執(zhí)行
#include typedef void(*FuncPtr)() ;
void p() { printf("MOP\n"); }
int main() { void (*ptr)(); p(); printf("%x\n",p); ptr = (void (*)())0x4110f0; ptr();//函數(shù)指針執(zhí)行 ((void (*)())0x4110f0)(); ((FuncPtr)0x4110f0)(); return 0; } 程序執(zhí)行結(jié)果如下: MOP4110f0MOP MOP MOP 首先定義一個(gè)ptr的函數(shù)指針,第一次通過函數(shù)名調(diào)用函數(shù),輸出Mop,打印函數(shù)的入口地址,函數(shù)的入口地址為4110f0。然后給函數(shù)指針ptr賦地址值為p的入口地址,調(diào)用ptr,輸出Mop。接著的過程是不通過函數(shù)指針直接執(zhí)行,仍然使用p的入口地址調(diào)用,輸出為MOP。最后是通過typedef調(diào)用的直接執(zhí)行。 函數(shù)名稱、代碼都是放在代碼段的,因?yàn)槭欠旁诖a段,每次會(huì)跳到相同的地方,但參數(shù)會(huì)壓棧,所以函數(shù)只根據(jù)函數(shù)名來獲取入口地址,與參數(shù)和返回值無關(guān)。無論參數(shù)和返回值如何不同,函數(shù)入口地址都是一個(gè)地方。 對以下程序進(jìn)行分析如下:
#include { return 3; }
int main() { printf("%x\n",p); int a = p(2,3); printf("%d\n",p); int b = p(4,5); printf("%x\n",p); return 0; } 程序輸出結(jié)果如下: 4111594264281411159 十六進(jìn)制的411159轉(zhuǎn)換成十進(jìn)制的值為4264281。程序中打印的p的入口地址,無論p是否調(diào)用函數(shù),入口地址都沒有改變。 分析如下代碼:
#include { return ((a>b)?a:b); } int main() { int (*ptr)(int ,int); ptr = (int (*)(int,int))0x411159; int c = ptr(5,6); printf("%d\n",c); return 0; } 程序輸出為 6 通過函數(shù)指針調(diào)用有返回值和參數(shù)的函數(shù),不適用函數(shù)名,而是用函數(shù)入口地址調(diào)用。 函數(shù)存放在內(nèi)存的代碼區(qū)域內(nèi),也有地址,一個(gè)函數(shù)在編譯時(shí)被分配一個(gè)入口地址,將這個(gè)入口地址稱為函數(shù)的指針,函數(shù)的地址就是函數(shù)的名字。函數(shù)指針不能指向不同類型或是帶不同形參的函數(shù)。 |
|