1

私が C# のデリゲートを学ぶとき、私の本はデリゲートが C の関数ポインターと同じであるが、より安全であると述べました。その行を読んだ後、私は次のように思います: ああ、C コンパイラは、関数ポインタが指すプロトタイプをチェックしません。そして、私は完全に間違っています。

int add(int a, int b){ return a + b; }
float add_f(float a, float b){ return a + b; }

int (*f)(int,int);
f = add; // no compile-error
f = add_f; //compile-error

その理由を教えてください。また、C# のデリゲートと比較して、C 関数ポインターが安全でないことを証明する例をいくつか教えてください。

ありがとう :)

4

2 に答える 2

4

C++ では、関数ポインターはタイプ セーフです。それらを壊すには、とてつもなくばかげたことをしなければなりません (通常、キャスト、共用memcpy体、または同様のものを使用します。偶然に起こることはありません)。

ただし、C では、関数の型はそれほど厳密ではありません。次のようなことができます。

int add(int a, int b){ return a + b; }
int add_f(float a, float b){ return a + b; }

int (*f)(); // empty argument list does NOT mean zero arguments.
            // for zero arguments, say int (*)(void)
f = &add;
f = &add_f;

http://ideone.com/Y6mCc


私は見事に愚かな例を求められました。 ここに行きます

#include <iostream>

int add(int a, int b){ return a + b; }
int add_f(float a, float b){ return a + b; }

union {
    int (*f1)(int, int);
    int (*f2)(float, float);
} fp;

int main(void)
{
    fp.f1 = &add;
    std::cout << "Expected (1): " << add(1, 3) << std::endl;
    std::cout << "Actual   (1): " << (fp.f1)(1, 3) << std::endl;

    std::cout << "Expected (2): " << add(1.0f, 3.0f) << std::endl;
    std::cout << "Actual   (2): " << (fp.f2)(1.0f, 3.0f) << std::endl;

    fp.f2 = &add_f;
    std::cout << "Expected (3): " << add_f(1.0f, 3.0f) << std::endl;
    std::cout << "Actual   (3): " << (fp.f2)(1.0f, 3.0f) << std::endl;

    std::cout << "Expected (4): " << add_f(1, 3) << std::endl;
    std::cout << "Actual   (4): " << (fp.f1)(1, 3) << std::endl;

    return 0;
}

このばかげたことは、C# でも同様に可能であることに注意してくださいMarshal.Copy

于 2012-07-09T18:53:04.253 に答える
1

C の関数ポインターと C# のデリゲートの類似点は、かなり表面的なものです。それらを機能ごとに比較すると、違いの長いリストが作成され、「安全性」はそのリストの一番上にはありません.

関数ポインターを使用して C# デリゲートをエミュレートする際の安全上の最大の問題は、関数ポインターが動作するデータの所有権です。デリゲートは静的関数に限定されないことを思い出してください。メンバー関数からデリゲートを生成できます。この場合、オブジェクトはデリゲートに「埋め込まれ」ます。C には同様の機能はありません。関数ポインタをデータに「バインド」するには、多くの作業を行う必要があります。後でデータが使用できなくなり、関数がそのデータを使用しようとすると、クラッシュが発生する可能性があります。しかし、その違いは、ガベージ コレクションと手動で管理されるメモリ環境の属性です。

于 2012-07-09T18:56:16.237 に答える