带有 void* 参数转换的函数指针

时间:2021-02-05 04:21:45

标签: c++ c pointers

我不知道如何查找,甚至标题也令人困惑,甚至我对我要查找的内容也感到困惑,而且这个问题肯定已经有人问过了,但它太具体了,所以这里有一些背景:

int comparison(const int* a, const int* b) {
    return *a - *b;
}

int main(int argc, char const *argv[])
{
    int arr[3] = {1,6,-2};
    qsort(arr,3,sizeof(int),comparison);
    return 0;
}

嗯,它确实有效,但是编译器给了我一个警告,因为 qsort 需要一个类型的函数:

int(*)(const void*, const void*) 

并且比较是一个函数类型:

int(*)(const int*, const int*) 

我想知道为什么编译器不高兴,因为它只需要强制转换地址。甚至应该很高兴为 void* 指针指定类型。这真的很糟糕吗?像未定义的行为之类的?或者只是编译器抱怨什么?

3 个答案:

答案 0 :(得分:2)

在给出其他原因之后,还有另一个原因。历史上有 void *int * 具有不同位安排的平台,我听说过 void *int * 的大小不同的传闻。该函数指针转换并不总是有效。

  const int *ia = (const int *)a;
  const int *ib = (const int *)b;

可能不会编译为 ia = a; 而是编译为 ia = a >> 1 之类的东西;所以真的必须有一个地方来放置这些说明。

答案 1 :(得分:1)

qsort 函数将您未传递的类型的函数作为其参数之一。所以你需要改变它。

在比较器中,您可以将指针重新转换为所需的类型。

此外,您需要 dereference 传递给比较器函数的 const int 指针的值:

#include <stdio.h>
#include <stdlib.h>

static int 
comparator(const void *a, const void *b) 
{
    return *(const int *)a - *(const int *)b;
}

static void
printArr(int arr[], int n) 
{ 
    int i; 
    for (i = 0; i < n; ++i) {
        printf("%d ", arr[i]);
    } 
} 

int
main(int argc, const char **argv)
{
    int arr[3] = {1, 6, -2};
    qsort(arr, 3, sizeof(int), comparator);
    printArr(arr, 3);

    return EXIT_SUCCESS;
}

答案 2 :(得分:1)

<块引用>

为什么他(编译器)不高兴。

qsort() 需要一个 int (*)(const void *a, const void *b) 类型的函数点,而不是 int (*)(const int *a, const int *b)。编译器可以猜测其OK并进行强制转换,但编译器警告此类问题的效率更高。

<块引用>

或者只是编译器抱怨什么?

通过温暖你,你可以确定问题的程度。


除了 @Alex Reynolds 好的答案,注意 *a - *b 可能会溢出,导致比较错误。

相反:

int comparison(const void *a, const void *b) {
  const int *ia = (const int *)a;
  const int *ib = (const int *)b;
  return (*ia > *ab) - (*ia < *ib);
}

优秀的编译器会识别 (p>q) - (p<q) 习语并发出高效的代码。

相关问题