2012-11-18 2 views
5

可能性の重複:を介して呼び出された場合に
Casting a function pointer to another typeCで定義されている関数ポインタ/法律で追加のパラメータを渡していますか?

は、機能は正常に実行されます、私は実際には、関数ポインタの定義を以下のパラメータを取る関数と関数ポインタを初期化すると仮定関数ポインタ?

私はgccでこれを試してみましたが、期待どおりに働いたが、その振る舞いはコンパイラ/プラットフォーム(私はそれがスタック上に大混乱をもたらすかもしれないいくつかのenviromentsに疑いがある)全体で一貫しているのだろうか:

#include <stdio.h> 

typedef void (*myfun)(int, int, int); 

void test_a(int x, int y, int z) { 
    printf("test_a %d %d %d\n", x, y, z); 
} 

void test_b(int x, int y) { 
    printf("test_b %d %d\n", x, y); 
} 

int main() { 
    myfun fp; 
    fp = test_a; 
    fp(1, 2, 3); 
    fp = (myfun) test_b; 
    fp(4, 5, 6); 
} 

答えて

4

あなたのプログラムの動作は未定義です。実際にコンパイルされるのは、コンパイラに「これは間違っているが、とにかくやっている」とキャストするキャストのためである。あなたはキャストを削除した場合は、適切なエラーメッセージが表示されます:

a.c:17:8: error: assignment from incompatible pointer type [-Werror] 

(。gcc -Wall -Werrorから)

具体的には、動作は呼び出し規約に依存します。あなたがプラットフォーム上にあった場合、議論がスタック上で「逆の」順序で渡された場合、プログラムは非常に異なる結果をもたらします。

+1

また、着信音のクリーンアップを使用するとクラッシュすることがあります。 –

+0

私は参照してください。 'typedef void(* myfun)() 'のように、パラメータリストなしで関数ポインタ型を定義するのはどうでしょうか?その場合、スタック上のパラメータの順序が「正しい」ことをコンパイラが保証するはずですか? – Askaga

+0

@BillAskaga No:あなたが望むものを「保証」するには、ターゲット関数と関数ポインタの両方が[cdecl呼び出し規則]を使用するようにする必要があります(http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl )。 – ChrisW

10

これは未定義の動作です。自己責任。使用されているcalling conventionに依存しますが動作するかどうかNasal Demons!

enter image description here

+0

この画像は素晴らしいです。ここでは、クリーンアップされたバージョンとベクタートレースを提供します:https://www.dropbox.com/sh/c0f5htyg46jcels/AABD9Qaw2JlhMAKCycAek-9ia?dl=0 – wilx

+0

Lol。ありがとうございました。私は、決心したくない私の好きな娘に、未定義の行動についての話をしました。彼女は翌日私にこれを送った。それについて愛するだけのことがあります。 – EvilTeach

+0

ここにJPGがあります:http://imgur.com/gallery/Zomm1zq/new – wilx

2

を引き起こすことが噂されています。

私はそれをお勧めしません。

3

関数呼び出しは未定義の動作です。

(C99,6.3.2.3p8) "[...]変換されたポインタを使用して、型が指し示し型と互換性のない関数を呼び出す場合、その動作は未定義です。

(C99、6.2.5p20)「は、[...]指定された戻り型を持つ関数を記述する関数型により特徴付け ある:機能タイプこと情報注

。その戻り値の型と、そのパラメータの数と種類」を参照してください。

関連する問題