在 C 中的这些函数指针之间进行转换是否安全?
Is it safe to convert between these function pointers in C?
在voidarg
和chararg
之间或voidarg
和fooarg
之间转换是否安全?:
typedef int (*voidarg)(void *);
typedef int (*chararg)(char *);
typedef int (*fooarg)(foo_t *);
或介于 voidret
和 charret
之间或介于 voidret
和 fooret
之间?:
typedef void *(*voidret)(int);
typedef char *(*charret)(int);
typedef foo_t *(*fooret)(int);
我知道这在 C++ 中可能不安全(特别是对于未知的 foo_t
类型),但根据任何 C 标准或主要 C 编译器,它是否安全?
编辑:
我忘了提一个重点。我也想调用这些函数,即能够做到这一点:
int charfunc(char *s) { /* ... */ }
char str[] = "...";
int somefunction(voidarg f, void *data)
{
return f(data);
}
int main()
{
int i = somefunction(charfunc, str);
}
我想您已经回答了您自己的问题:不,这不安全。如果你正在转换 voidarg(从和到)你实际上是在告诉编译器你知道你在做什么。
这是编译器给你的灵活性,但你必须为正确的转换付出代价。
我希望转换是安全的,前提是指针在调用之前被转换为正确的类型。这还假设它们都使用相同的调用约定装饰声明。
我在我的运算符构造函数中完成了此操作 here,该函数以 "generic" 形式存储各种函数类型,但它们在运算符执行函数中被强制转换为正确的类型。这似乎适用于 Cygwin/mingw/Ubuntu 中的 gcc、适用于 solaris 的 suncc 和 Visual Studio。我的替代方案是非原型函数指针,它给了我大量嘈杂的编译器警告。
对于更新, 不,至少从可移植性的角度来看,这对我来说并不安全。通过错误类型的指针调用函数是未定义的行为。 void *
类型能够存储指向任何对象类型的指针(不一定是函数,但这不是这里的问题)。并且函数指针能够存储不同签名的函数指针,但是通过错误的类型调用 可能 实现类似 "reinterpret_cast" 的东西,否则它可能会崩溃。
在voidarg
和chararg
之间或voidarg
和fooarg
之间转换是否安全?:
typedef int (*voidarg)(void *);
typedef int (*chararg)(char *);
typedef int (*fooarg)(foo_t *);
或介于 voidret
和 charret
之间或介于 voidret
和 fooret
之间?:
typedef void *(*voidret)(int);
typedef char *(*charret)(int);
typedef foo_t *(*fooret)(int);
我知道这在 C++ 中可能不安全(特别是对于未知的 foo_t
类型),但根据任何 C 标准或主要 C 编译器,它是否安全?
编辑:
我忘了提一个重点。我也想调用这些函数,即能够做到这一点:
int charfunc(char *s) { /* ... */ }
char str[] = "...";
int somefunction(voidarg f, void *data)
{
return f(data);
}
int main()
{
int i = somefunction(charfunc, str);
}
我想您已经回答了您自己的问题:不,这不安全。如果你正在转换 voidarg(从和到)你实际上是在告诉编译器你知道你在做什么。
这是编译器给你的灵活性,但你必须为正确的转换付出代价。
我希望转换是安全的,前提是指针在调用之前被转换为正确的类型。这还假设它们都使用相同的调用约定装饰声明。
我在我的运算符构造函数中完成了此操作 here,该函数以 "generic" 形式存储各种函数类型,但它们在运算符执行函数中被强制转换为正确的类型。这似乎适用于 Cygwin/mingw/Ubuntu 中的 gcc、适用于 solaris 的 suncc 和 Visual Studio。我的替代方案是非原型函数指针,它给了我大量嘈杂的编译器警告。
对于更新, 不,至少从可移植性的角度来看,这对我来说并不安全。通过错误类型的指针调用函数是未定义的行为。 void *
类型能够存储指向任何对象类型的指针(不一定是函数,但这不是这里的问题)。并且函数指针能够存储不同签名的函数指针,但是通过错误的类型调用 可能 实现类似 "reinterpret_cast" 的东西,否则它可能会崩溃。