ISO C Void*和功能指针

Tom*_*ory 16 c function-pointers void-pointers

在学习了一些教程并阅读有关函数指针的内容后,我了解到显然在ISO C中为函数指针指定了一个void指针是未定义的,有没有办法解决我在编译期间收到的警告(例如更好的编码方式)或我应该忽略它吗?

警告:

ISO C forbids assignment between function pointer and 'void *' [-pedantic]
Run Code Online (Sandbox Code Playgroud)

示例代码:

void *(*funcPtr)();
funcPtr = GetPointer();
Run Code Online (Sandbox Code Playgroud)

GetPointer是一个返回void指针EG的函数

void *GetPointer();
Run Code Online (Sandbox Code Playgroud)

小智 9

tlpi-book中我发现这个技巧非常有趣:

#include <dlfcn.h>

int
main(int argc, char *argv[])
{
    ...
    void (*funcp)(void);        /* Pointer to function with no arguments */
    ...
    *(void **) (&funcp) = dlsym(libHandle, argv[2]);
}
Run Code Online (Sandbox Code Playgroud)

  • @MatthieuPoullet:在右侧,我们有一个空指针(`void *`)。在左侧,我们获取函数指针的地址。暂时忽略 `(void **)`,指向函数指针的指针被最左边的 `*` 解除引用。`(void **)` 只是说指向函数指针的指针应该被转换为指向 void 指针的指针,当被最左边的 `*` 取消引用时,它就是一个 `void *`。因此,赋值的左侧和右侧都有类型 `void *`,编译器很高兴。 (3认同)
  • 这是严格的混叠违规,因此具有未定义的行为。即使通过使用“ memcpy”解决了该问题,我们仍然会依赖一些我们不应该依赖的东西,即函数指针的二进制表示形式与数据指针的表示形式相同。最好只是进行常规强制转换,并在本地禁用-Wpedantic。我不建议通过做更糟糕的事情来解决警告,即编译器恰好没有警告。 (2认同)

小智 7

编号是正确的,您也是:在C89和C99中,您无法在数据指针(即void *)和函数指针之间进行转换,因此解决警告的唯一方法是从函数返回一个函数指针.

(但请注意,实际上尽管有警告,这仍然有效,即使标准库中存在这种不一致 - 该dlsym()函数用于获取函数指针,但它返回void *- 所以基本上你可以忽略警告.它会工作,虽然严格来说,这里的行为是不明确的.)

  • "在实践中这是有效的"在大多数架构上.有一些(主要是神秘的)架构无法正常工作.另外``dlsym`不是"标准库"函数,它是一个Unix库函数.并且它不是"语言错误的东西",因为它有一个原因(某些地方不起作用). (4认同)

小智 5

我在使用glib时遇到了这个问题。Glib 数据结构,例如 GSList,通常有一个名为 void *data 的字段。我想将函数存储在列表中,但遇到了一堆与此类似的错误:

\n\n
warning: ISO C forbids passing argument 2 of \xe2\x80\x98g_slist_append\xe2\x80\x99 between function pointer and \xe2\x80\x98void *\xe2\x80\x99 [-pedantic]\n
Run Code Online (Sandbox Code Playgroud)\n\n

此示例使用 gcc -Wall -ansi -pedantic 生成一堆警告

\n\n
typedef int (* func) (int);\n\nint mult2(int x)\n{\n    return x + x;\n}\n\nint main(int argc, char *argv[])\n{\n    GSList *functions = NULL;\n    func f;\n\n    functions = g_slist_append(functions, mult2);\n    f = (func *) functions->data;\n    printf("%d\\n", f(10));\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

所以我将函数包装在一个结构中,所有警告都消失了:

\n\n
struct funcstruct {\n    int (* func) (int);\n};\n\nint mult2(int x)\n{\n    return x + x;\n}\n\nint main(int argc, char *argv[])\n{\n    GSList *functions = NULL;\n    struct funcstruct p;\n    p.func = mult2;\n\n    functions = g_slist_append(functions, &p);\n    p = * (struct funcstruct *) functions->data;\n    printf("%d\\n", p.func(10));\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

可以说,这是相当多的额外代码,可以使一些警告消失,但我不喜欢我的代码生成警告。另外,以上只是玩具示例。在我正在编写的实际代码中,事实证明将函数列表包装在结构中非常有用。

\n\n

我很想知道这是否有问题或者是否有更好的方法。

\n