Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 函数指针类型如何不安全_C++ - Fatal编程技术网

C++ 函数指针类型如何不安全

C++ 函数指针类型如何不安全,c++,C++,首先,类型安全意味着,如果操作不正确,编译器可以立即捕获任何内容 现在,我听说函数指针不是类型安全的,但是每当我试图错误地使用它们时,编译器都会为我报告错误。那么,它是如何不安全的呢 例如,这是一个接受函数指针的函数原型 void SortElements(void* MyArray, unsigned int iNumofElems,size_t size, int(*compare_funct)(void* First,void* SecondElem)) 我定义了几个传递给它的函数: i

首先,类型安全意味着,如果操作不正确,编译器可以立即捕获任何内容

现在,我听说函数指针不是类型安全的,但是每当我试图错误地使用它们时,编译器都会为我报告错误。那么,它是如何不安全的呢

例如,这是一个接受函数指针的函数原型

void SortElements(void* MyArray, unsigned int iNumofElems,size_t size, int(*compare_funct)(void* First,void* SecondElem))
我定义了几个传递给它的函数:

int MySortAsc(void* First, void* Second);
void MyFunct2();
void MyFunct3(void* First);
该代码仅编译用于:

SortElements(MyArray, 10, sizeof(DataType), &MySortAsc); //Compiles
SortElements(MyArray, 10, sizeof(DataType), &MyFunct2);  //Fails
你知道我怎么会在这里误用函数指针吗

是否因为这个原因:

void (*functionPointer)();
...
int integer = 0xFFFFFFFF;     
functionPointer = (void(*)())integer;      
functionPointer();
答复:
我看到的是C++中的函数指针是类型安全的。当然,它们可以通过不直接地强制转换来以不安全的方式使用,但这并不能使它们成为被称为类型不安全的理由。NET委托也是强类型的,在我看来两者都是类型安全的。

函数指针实际上是类型检查的,并且是类型安全的。

函数指针是类型安全的。然而,许多环境迫使程序员需要重新编写它们。不正确的强制转换可能会导致严重的问题。

nesC(TinyOs中使用的C方言)强烈反对函数指针,因为它们会阻碍优化。在这里,静态代码分析(或者说缺乏适用性)比类型安全性更令人担忧,但我不确定这些问题是否会被混淆

另一个问题可能是将函数指针用作事件处理程序。当使用通用事件调度器时,您可能希望从适当的类型中抽象出来,这意味着您可以考虑将函数指针存储为
void*
,这仅仅是为了模块化。这将是函数指针的类型不安全用法而不是类型安全动态绑定用法的一个突出例子

那么,它是如何不安全的呢

您显示的代码类型不安全,这不是因为函数指针,而是因为在
SortElements
签名和函数指针签名中使用了
void*

struct Apple {
   int weight;
};
struct Pear {
   double weight;
};
int compare_pears( void * pear1, void * pear2 ) {
   return static_cast<Pear*>(pear1)->weight - static_cast<Pear*>(pear2)->weight;
}
int main() {
   Apple apples[10];
   SortElements( apples, 20, sizeof(Pear), compare_pears );
}
这是不安全的原因是调用方负有传递正确参数的全部责任,并且编译器无法确保指针
MyArray
指向一个连续内存区域,该区域包含
iNumofElems
,每个iNumofElems都具有接口中提供的
大小。如果程序员犯了错误,编译器将无法提供帮助,如果维护人员修改数组中存储的类型(大小更改)或元素数量,编译器将无法检测到它并告诉您需要更新对
SortElements
的调用。最后,由于传递的函数指针也使用了
void*
,因此比较苹果和梨的比较器的签名完全相同,如果传递的函数指针不正确,编译器将无能为力

struct Apple {
   int weight;
};
struct Pear {
   double weight;
};
int compare_pears( void * pear1, void * pear2 ) {
   return static_cast<Pear*>(pear1)->weight - static_cast<Pear*>(pear2)->weight;
}
int main() {
   Apple apples[10];
   SortElements( apples, 20, sizeof(Pear), compare_pears );
}

你不能弄错数组的大小或元素的大小,如果有人更改类型
Apple
,编译器将拾取它,如果数组的大小更改,编译器将拾取它。您不能错误地使用传递给函数的比较器,因为编译器也会选择它。现在,程序是类型安全的,即使它使用函数指针(这可能会影响性能,因为它们会抑制内联,这就是为什么
std::sort
通常比
qsort
快的原因)

您在哪里看到它被描述为不安全的?查看源代码将有助于理解作者的意图。“类型安全”意味着一段代码的正确性仅取决于它的静态类型,而不依赖于变量的特定值。例如,
printf
不是类型安全的,因为它的正确性取决于格式字符串的值以及它的参数类型。那么为什么告诉它与普通函数指针相比,.NET委托是类型安全的函数指针呢?@KerrekSB:这里不是这样的。Printf是不安全的,因为省略号是一个不维护类型的包罗万象(即调用方和被调用方必须就如何解释类型达成一致。函数指针从这个角度来看是安全的,即使在这种特殊情况下,由于其他原因,它是不安全的:使用<代码> Value*/Cult>中断类型安全性。@ DavIDRODR Guez DReBeas,我总是可以在C++中进行铸造,并打破我所示的类型安全性。在上面的示例中,如果调用functionPointer()程序将崩溃。据我所知,在.NET委托中,你不能这样做。从这个意义上说,这会使函数指针不安全吗?这是一个很好的解释。因此,函数指针本质上是类型安全的,这取决于它们的使用方式,这会使它们做不安全的事情,就像我的示例中的情况一样?不,我不会这么说。有趣Action指针是类型安全的。任何代码(不限于函数指针)在开始强制转换时都可能是类型不安全的。正是强制转换使事情变得不安全。函数指针绝对没有与类型安全相关的特殊属性。@FrankQ。代码中的类型安全问题来自于函数接口的设计,即emoves类型信息,而不是从传递函数指针的事实中。通过隐式转换到
void*
删除正确的类型意味着管理内存中每个位的类型的负担落在程序员的手中(转换)没有编译器的任何帮助来验证正确性。还要注意,前面没有提到,该函数只能以位的形式管理数据,这意味着您将导致除POD以外的任何对象的未定义行为。(即,
sorteElements
可以移动位,但不能移动对象,它将无法应用用户定义的拷贝/移动)
template <typename T, std::size_t N>
void SortElements( T (&array)[N], int (*cmp)( T const &, T const & ) );
int compare_pears( Pear const & lhs, Pear const & rhs );
int compare_apples( Apple const & l, Apple const & r );
Apple array[10];
//SortElements( array, compare_pears );   // Error!!!!
SortElements( array, compare_apples );    // Good!