代码之家  ›  专栏  ›  技术社区  ›  Pruzo

K&R 5.11函数指针C中的混淆线

  •  5
  • Pruzo  · 技术社区  · 9 年前

    中该行的最后一个参数 main() 让我迷路

    // declaration
    void qsort(char *linep[], int left, int right, int (*compare)(void *, void*);
    
    // use
    main(){
        qsort((void**) lineptr, 0, nlines-1, (int (*)(void*,void*))(numeric ?
        numcmp : strcmp));
    }
    

    我理解三元运算符,但假设numeric==0,那么这意味着什么?

    (int (*)(void *, void*))strcmp;
    

    函数参数的数据类型是否不匹配?

    int strcmp(const char*, const char*);
    void qsort( , , , int(*)(void*)(void*);
    

    我可以键入函数指针吗?

    2 回复  |  直到 9 年前
        1
  •  5
  •   Sourav Ghosh    9 年前

    在代码中,使用

      (int (*)(void *, void*))strcmp;
    

    方法 , strcmp() 是一个函数指针,它需要两个 void * 参数并返回 int .

    通常,对于函数指针,强制转换是一个非常糟糕的主意,因为引用 C11 ,第§6.3.2.3章

    […]如果转换 指针用于调用其类型与引用类型不兼容的函数, 行为未定义。

    但是,在您的情况下,对于参数类型, char * 空隙,空隙* 彼此别名,因此类型转换类型为 可共用的 实际有效类型,因此( 稍后 )定义了函数调用。

        2
  •  1
  •   Peter - Reinstate Monica    9 年前

    是的,您可以将函数指针强制转换为指向具有不同签名的函数的指针。取决于您的调用约定(谁清理堆栈?调用者还是被调用者?)如果参数数量不同或大小不同,则调用该函数会很糟糕。

    这里也不是这样:在您的标准架构(sun工作站、Linux PC、树莓PI)上,指向不同数据类型的参数指针表示相同,因此不会造成任何伤害。该函数将从堆栈中读取4或8字节的值,并将指向的内存解释为预期类型的数据(但它应该具有这种类型,例如,不要对字符串使用浮点比较函数;它可能会抛出,因为任意位模式可以是NaN等)。

    我想提醒你,今天的标准库 qsort 具有与K&R的例子。今天的 快速排序 获取指向元素向量开头的指针,并使用指向数组中元素的指针调用比较函数;对于字符串指针数组,参数为 指针到指针 它们不适合 strcmp() 。必须首先取消引用参数。这个 linux man page for qsort 有一个示例 strcmp 包装器就是这样做的。(手册页web导出看起来有些混乱,但仍然可读。)