2012-01-28 16 views
5

次のコードは、私がしようとしていることを記述していると思います。具体的には、汎用ポインターの型が異なるだけで、汎用ポインターを汎用ポインターにキャストしたいと思っています。異なるポインタ型の引数ポインタとしてのキャスト関数ポインタ

は今、私はthis questionで説明したように互換を可能にする関数ポインタのための要件が​​あることを認識してんだけど、私は別のポインタ型を満たす互換性要件の引数を持つかどうかはわかりません。

コードはコンパイルされて実行されますが、期待通りに、互換性のないポインタ型からの割り当てに関する警告が表示されます。コンパイラを満足し、私が何を達成するための方法がありますか?

#include <stdio.h> 

int float_function(float *array, int length) 
{ 
    int i; 
    for(i=0; i<length; i++){ 
     printf("%f\n", array[i]); 
    } 
} 

int double_function(double *array, int length) 
{ 
    int i; 
    for(i=0; i<length; i++){ 
     printf("%f\n", array[i]); 
    } 
} 


int main() 
{ 
    float a[5] = {0.0, 1.0, 2.0, 3.0, 4.0};  
    double b[5] = {0.0, 1.0, 2.0, 3.0, 4.0}; 

    int (*generic_function)(void*, int) = NULL; 

    generic_function = &float_function; 
    generic_function(a, 5); 

    generic_function = &double_function; 
    generic_function(b, 5); 

    return 0; 
} 

答えて

5

最もきれいな方法は、の内部にの機能を実行するIMHOです。これにより、すべての関数シグネチャが同じになり、呼び出し元のコードからキャストが保持されます。 (これは例えばqsort()が望む方法です)

int double_function(void *p, unsigned size) 
{ 
    double *array = p  
    unsigned uu; 

    for(uu=0; uu < size; uu++){ 
     printf("%f\n", array[uu]); 
    } 
return 42; 
} 
+0

確かに、私はそれについて考えていました。問題は私がライブラリを呼び出すことである(それ自体が問題のスタック全体を持つかもしれない!)。したがって、私は別々に呼び出すそれぞれの関数をラップする必要があります。これは、私が避けようとしていたものです(内部ロジックを単純にしていますが)。 –

+0

私はライブラリ関数の事例を考えていませんでした。コンパイラと人間の読者の両方を満足させるのは難しいでしょう。たぶん、ラッパー関数(または醜いプリプロセッサハック;-)は正しい方法です。 – wildplasser

+0

私はラッパー関数が最もクリーンな方法であることに同意します。もう少しコードがありますが、論理的に分かれています。また、署名を変更してラッパーにコードを含めることもできます。 –

1

EDIT:@Matが指摘するように、Cの仕様に従うことを、あなたはかなりあまり有用でこの全体の運動しをすることになる、それを呼び出す前に、元の型に戻す関数ポインタをキャストする必要があるだろう;

((int(*)(float*,int))generic_function)(a, 5); 

(@wildplasserからの回答に触発された)別の解決策は、void *型を取り、代わりにそのパラメータにキャストを実行する機能で関数をラップすることです。それを "マクロで"行うのはかなりシンプルです。

#define WRAP(FN, TYPE) int FN##_wrapped(void* p, int len) { return FN((TYPE*)p, len); } 
WRAP(float_function, float) 
WRAP(double_function, double) 

次に、代わりに次のきれいな行を使用できます。つまり、ポインタのキャストは一般的に私が主張している解決策ではありませんが、その使用例があります。

+1

これは、コンパイラをシャットダウンするだけです(ラグの下の問題を隠します)。良いアドバイスIMO。 – Mat

+0

コンパイラがシャットダウンしてはならないというテクニックには固有の問題がありますか? –

+1

はい、互換性のない関数ポインタ型の間でキャストし、実際の型にキャストせずにキャスト関数を呼び出しています。これは、標準に従った未定義の動作です。 – Mat

2

はい、プロトタイプなしで宣言してください。

int (*generic_function)() = NULL; 

は今、あなたはintを返す任意の機能を割り当てることができます、だけでなく、任意の引数を渡すことができますし、コンパイラは、互換性のない引数を拒否するために必要とされていません。

+0

しかし、これは、関数ポインタとしてstrcmp()またはfprintf()へのポインタを使用しようとすると、コンパイラが文句を言うことがないという欠点があります。 – wildplasser

+0

@wildplasserこれはパラメータタイプとして 'void *'を使うときと同じ問題です。本体に 'double * 'などが必要なときに' int * 'を渡すことはできます。 –

+0

はい、それは正しいです。しかし、コンパイラー*は、引数として1つのポインターと1つのintが渡されているかどうかを少なくともチェックすることができます。 – wildplasser

関連する問題