C:函数指针不安全的例子与C#的委托比较

时间:2012-07-09 18:50:36

标签: c# c delegates function-pointers

当我学习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#中的委托相比是不安全的。

谢谢:)

2 个答案:

答案 0 :(得分: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


我被问到一个非常愚蠢的例子。 Here goes

#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;
}

请注意,使用Marshal.Copy的C#同样可以实现这种愚蠢。

答案 1 :(得分:1)

你不应该把每本书的内容都用于它的面值:C的函数指针和C#的代表之间的相似性是相当肤浅的。比较它们的特征到功能将产生一个差异的清单,“安全”将远离该列表的顶部。

使用函数指针模拟C#委托的最大安全问题是函数指针操作的数据的所有权。回想一下,委托不限于静态函数:您可以从成员函数生成委托,在这种情况下,对象将“嵌入”委托中。 C中没有类似的功能:你需要做很多工作才能将函数指针“绑定”到一段数据。如果数据稍后变得不可用,并且该函数尝试使用该数据,则可能会触发崩溃。但这种差异是垃圾收集与手动管理的内存环境的一个属性。