函数指针强制转换为不同的签名 [英] Function pointer cast to different signature

查看:161
本文介绍了函数指针强制转换为不同的签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用函数指针的结构来实现对不同的后端的接口。该签名有很大的不同,但返回值几乎都是无效的,无效*或int类型。

I use a structure of function pointers to implement an interface for different backends. The signatures are very different, but the return values are almost all void, void * or int.


struct my_interface {
    void  (*func_a)(int i);
    void *(*func_b)(const char *bla);
    ...
    int   (*func_z)(char foo);
};

但是它不要求一个后端支持的每个接口功能的功能。所以,我有两种可能,第一种选择是,如果指针为NULL不平等每次调用前检查。我不喜欢非常多,因为可读性,也因为我担心对性能的影响(我还没有测不过它)。另一种选择是有一个虚设的功能,为罕见的情况下的接口功能不存在。

But it is not required that a backends supports functions for every interface function. So I have two possibilities, first option is to check before every call if the pointer is unequal NULL. I don't like that very much, because of the readability and because I fear the performance impacts (I haven't measured it, however). The other option is to have a dummy function, for the rare cases an interface function doesn't exist.

所以我需要为每一个签名的虚拟函数,我不知道是否有可能仅具有一个不同的返回值。它投给定的签名。

Therefore I'd need a dummy function for every signature, I wonder if it is possible to have only one for the different return values. And cast it to the given signature.


#include <stdio.h>

int nothing(void) {return 0;}

typedef int (*cb_t)(int);

int main(void)
{
    cb_t func;
    int i;

    func = (cb_t) nothing;
    i = func(1);

    printf("%d\n", i);

    return 0;
}

我测试code用gcc和它的作品。但它是理智?还是可以破坏栈还是可以引起其他问题?

I tested this code with gcc and it works. But is it sane? Or can it corrupt the stack or can it cause other problems?

编辑:感谢所有的答案,现在我学到了很多关于调用约定,有点进一步阅读之后。而现在有一个更好的了解的引擎盖下会发生什么。

Thanks to all the answers, I learned now much about calling conventions, after a bit of further reading. And have now a much better understanding of what happens under the hood.

推荐答案

由C规格,铸造不确定的行为函数指针的结果。事实上,有一阵子,GCC 4.3 prereleases将由规范返回NULL,只要你铸造一个函数指针,完全有效的,但他们退出了发布之前的变化,因为它打破了很多的方案。

By the C specification, casting a function pointer results in undefined behavior. In fact, for a while, GCC 4.3 prereleases would return NULL whenever you casted a function pointer, perfectly valid by the spec, but they backed out that change before release because it broke lots of programs.

假设GCC继续做它,现在,它会正常工作使用默认的x86调用约定(和大多数调用约定在大多数架构),但我不会依赖于它。在每次调用点测试针对空函数指针不超过一个函数调用昂贵得多。如果你真的想要,你可以写一个宏:

Assuming GCC continues doing what it does now, it will work fine with the default x86 calling convention (and most calling conventions on most architectures), but I wouldn't depend on it. Testing the function pointer against NULL at every callsite isn't much more expensive than a function call. If you really want, you may write a macro:

#define CALL_MAYBE(func, args...) do {if (func) (func)(## args);} while (0)

或者你可以对每一个签名的不同的虚拟函数,但我能理解你想避免这一点。

Or you could have a different dummy function for every signature, but I can understand that you'd like to avoid that.

查尔斯·贝利叫我出这一点,让我去,抬头细节(而不是依靠我的多孔内存)。该 C规范说:

Charles Bailey called me out on this, so I went and looked up the details (instead of relying on my holey memory). The C specification says

766的指针一种类型的功能可以被转换为一个指针到另一种类型的,然后再返回的函数;

  767的结果应比较等于原始指针。

  768如果转换后的指针可以用来调用其类型与指向的类型,其行为是未定义兼容的功能。

766 A pointer to a function of one type may be converted to a pointer to a function of another type and back again;
767 the result shall compare equal to the original pointer.
768 If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined.

和GCC 4.2 prereleases(这是4.3之前解决方式)是遵循以下规则:函数指针的演员并没有导致NULL,因为我写的,而是试图通过一个不兼容的类型调用一个函数,即

and GCC 4.2 prereleases (this was settled way before 4.3) was following these rules: the cast of a function pointer did not result in NULL, as I wrote, but attempting to call a function through a incompatible type, i.e.

func = (cb_t)nothing;
func(1);

这是你的榜样,将导致中止。他们改回4.1行为(允许,但警告),部分原因是这一变化打破了OpenSSL的,但OpenSSL的已被固定在此期间,这是不确定的行为,编译器是免费的在任何时候改变。

from your example, would result in an abort. They changed back to the 4.1 behavior (allow but warn), partly because this change broke OpenSSL, but OpenSSL has been fixed in the meantime, and this is undefined behavior which the compiler is free to change at any time.

OpenSSL的只是铸造的功能指向其他函数类型采取和返回相同数量完全相同的尺寸值,而这个(假设你不处理浮点)刚好是跨所有平台安全调用约定,我知道的。然而,什么都可能是不安全的。

OpenSSL was only casting functions pointers to other function types taking and returning the same number of values of the same exact sizes, and this (assuming you're not dealing with floating-point) happens to be safe across all the platforms and calling conventions I know of. However, anything else is potentially unsafe.

这篇关于函数指针强制转换为不同的签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆