2013-02-03 19 views
-4

我想了解什麼是指向c中函數的指針。理解調用指向函數的指針

我想要一些調用函數指針的詳細過程,因此,我可以更好地理解指向函數的指針。

有人可以解釋爲什麼我的代碼下面不會崩潰,並有一些有線輸出? 要縮小,我正在尋找類似javap這可以解釋如何jdk編譯 我的代碼和jvm我的代碼運行

  1. 什麼是void返回和號碼14,15或16 的關係(無效函數返回)
  2. 是否有任何安全問題,我的第二個參數或是非相同的非初始化val?

test.c的

#include <stdio.h> 
#include <stdlib.h> 


static void f(int x, int y){ 

    printf("x = %d \n", x); 
    printf("y = %d \n", y); 
} 

typedef int (*FUNC)(int); 

int main(void){ 

    long int addr = (long int)f; 
    printf("%d \n", (int)((FUNC)addr)(1)); 

    return 0; 
} 

在Mac OS輸出編譯i686-apple-darwin11-llvm-gcc-4.2

x = 1 
y = 1479046720 
16 
+0

指向一個功能僅僅是一個存儲在一個變量函數的引用方式,讓您可以在功能再打。因爲它是一個變量,而不是一個固定的調用,所以可以在運行時更改要調用的函數,但就是這樣。沒有涉及的魔法。 –

+0

看到http://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work – farmer1992

回答

4

答案是不確定的行爲。您正在使用兩個不兼容的函數指針類型,並使用一個來調用另一個。 (更不用說將指針存儲在一個整數等等)因此,你的程序調用未定義的行爲,因此,任何事情都可能發生。你得到的值很可能只是亂糟糟堆棧和/或CPU寄存器中的隨機垃圾。

3

您造成不確定的行爲所有的地方:

  • 要存儲的函數指針的整數,這是不保證工作
  • 你強制轉換爲不同的整數表示用不同的返回類型
  • 你打電話用較少的參數功能比它預計
  • 你把返回值從函數返回void函數指針(參數少)的類型

試圖讓感這僅僅是不合理的,但作爲一個猜測,因爲你正在使用的x86:

  • x正確填充在功能與1你通過
  • y不所以它得到一個隨機值,可能會在堆棧上一些吃剩的
  • 沒有返回值,你會得到什麼留在AX寄存器

有人能解釋爲什麼我下面的代碼不會崩潰,並有一些 有線輸出

做錯事不能保證你的程序崩潰 - 沒有保證。

+1

「試圖有道理的,這只是不合理的」 - 同意。究竟。 – 2013-02-03 11:11:59

+0

謝謝我只是想要一些現象來幫助我理解指向函數的指針 – farmer1992

0

你回到過去的輸出值16可能是由printf的寫入的字符數 - 因爲這就是printf的回報,在這種情況下,沒有別的之後,在功能發生。但是,像其他人所說的,你問發生了什麼,沒有人能真正說 - 它可能不會在所有的工作,玉石俱焚,或給你一些「隨機」值作爲回報,打印 - 這不是在任何地方定義,如果您使用不同的編譯器,不同的編譯器設置或不同類型的硬件編譯代碼,結果會改變。

每次運行代碼時,它很可能給你相同的結果,但作出一些修改代碼,並會出現不可預知的結果。

0

要回答這個問題,

有人能解釋爲什麼我下面的代碼不會崩潰

並不是所有的斷碼的實際崩潰。可能f的參數(和返回值)在寄存器中被傳遞,而不是被壓入堆棧,並且因此預期值和實際值之間的不匹配不翻譯成堆疊的未對準。如果您嘗試了更多的參數,足以要求堆棧工作,那麼您可能會遇到崩潰或某種可能的危險行爲(畢竟,在某些安全漏洞中也會使用類似的技術)。

然後澄清函數指針的用法,我已與一對夫婦的意見重寫代碼的自由。

#include <stdio.h> 
#include <stdlib.h> 

/* We want to be able to print a return value, so we make 
    f return something - a long, so as to tell it from int 
    - in order to be able to get something back. 
*/ 

static long f(int x, int y){ 

    printf("x = %d \n", x); 
    printf("y = %d \n", y); 
    return x + y; 
} 

/* We want the signature of a function returning long, and taking 
    two int's, since this is what f() is. 
*/ 
typedef long (*FUNCPTR)(int, int); 
typedef long (FUNC)(int, int); 

int main(void) 
{ 
    /* We want a pointer to f - it works either way */ 
    FUNCPTR addr = f; 
    FUNC *addr2 = f; 

    /* addr points to a function taking two ints, so we must pass it 
     two ints, and format return as long decimal */ 

    printf("%ld\n", addr(5, 7)); 

    /* addr2 is the same */ 

    printf("%ld\n", addr2(5, 7)); 

    return 0; 
} 

預期輸出:

$ gcc -W -Wall -o test test.c 

$ ./test 
x = 5 
y = 7 
12 
x = 5 
y = 7 
12