调用强制类型转换后的函数指针是否安全?

6
特别是,以下内容是否会如预期般正常运行:
typedef void(*func_p)(void*);

void foo(int* data)
    {
    printf("%i\n",*data);
    }

int main(int argc, char** argv)
    {
    func_p bar;
    int x = 42;

    bar = foo;
    bar((void*)&x);

    return 0;
    }

我可以依赖数据指针 (void*, int*, struct baz*, 但不一定是 void(*)(void)) 总是兼容传递吗?


有没有一种订阅问题的方式,这样当它被回答时你会收到通知,而不必留下这些愚蠢的评论并跟踪它? - Ramadheer Singh
@Gollum:点击空心星号。然后通过点击顶部的信封,在“最近更改”页面的“收藏夹”选项卡中查看任何更改。 - SLaks
2个回答

7
这不是标准所要求的。标准要求char*void*具有相同的表示和对齐要求,所有结构体指针和联合体指针也是如此。虽然在任何情况下调用转换后的函数指针都是未定义行为(§6.5.2.2p9),但是相同的表示和对齐要求确保了调用的实际效果(§6.2.5p27)。
其他指针类型不需要以这种方式行事,尽管我个人没有遇到过这样的机器。例如,理论上可能会出现int*char*sizeof更小的情况(如果int具有比char更严格的对齐要求,则这可能是合理的)。在正确的调用约定下,在这样的机器上调用转换后的函数指针将实际上是不可能的。

@David 说实话,如果这意味着我需要创建几十个包装函数才能将我的函数作为参数传递给这样的类型,那我宁愿进行强制转换 :) - Johannes Schaub - litb
@litb,因为这个原因我已经这样做了一段时间了:] - David X
5
void foo(void *p) { int *data = p; ... } 是可以的。 - caf
@caf 是的,绝对没错。如果你有更改被调用函数的选择,那就这么做吧。 - Johannes Schaub - litb

1
除非你的代码针对古怪的古老大型机,否则在实际应用中它会正常工作。现代计算机不会使用不同的表示来处理不同的指针类型,而且我认为未来也不太可能出现这种情况。这种做法简直是不合逻辑和倒退的,就像一补数算术一样。
如果你仍然担心或想满足语言纯粹主义者的要求,可以按照caf的建议进行操作。

我曾经认为指向函数的指针可能与指向数据的指针大小不同,这是C++的特性吗? - kibibu
这是与 Microsoft 的“内存模型”和近/远指针相关的 16 位 Windows 事物。需要澄清的是:标准允许它们不同,但在现代架构上它们永远不应该不同。 - R.. GitHub STOP HELPING ICE
@kibibu @R.. 实际上,在微控制器和类似设备上,函数指针比数据指针更大是相当常见的,因为程序存储器可能与数据存储器分开,或者不可写。 - David X

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接