请考虑以下代码:
void f() {};
void* v = f;
int i = f;
int main() { }
为什么将函数地址存储到int
变量中会给我一个error:
错误:初始化元素不是编译时常量
但是对于void*
变量没有?
答案 0 :(得分:3)
在文件范围(" global")声明的变量具有静态存储持续时间。
具有静态存储持续时间的所有变量必须初始化为编译时常量。在C中,其他变量(甚至不是const
个)不算作编译时常量,因此就是错误。
此外,您不能指定一个整数的指针,这样做无效C.您必须先通过强制转换将指针手动转换为整数类型。
此外,演员void* v = f;
没有明确定义。 C标准仅指定void*
和指向对象类型的指针之间的强制转换。
现在你应该做些什么来获得一个函数的地址:
#include <stdint.h>
uintptr_t i = (uintptr_t) f;
int main (void)
{ ...
保证 uintptr_t
足够大以包含任何指针的地址。
答案 1 :(得分:2)
当我编译它时,我得到:
$ gcc foo.c
foo.c:3:5: warning: incompatible pointer to integer conversion initializing 'int' with an expression of type 'void ()' [-Wint-conversion]
int i = f;
^ ~
foo.c:3:9: error: initializer element is not a compile-time constant
int i = f;
^
1 warning and 1 error generated.
真的,我认为这个警告应该是一个错误。你试图将一个地址放入一个整数,这通常是不好的形式。
也就是说,如果编译器继续进行转换,结果不是编译时常量(因为它是转换后的值)。因此错误。
虽然你不是在问C ++,但我很好奇这两种语言是如何不同的,所以我检查了我的编译器的行为方式。在那种语言中,f
的两项任务都是非法的,这是有充分理由的。 void*
不是指向无参数函数的指针,int
也不是。
$ g++ foo.c
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated
foo.c:2:7: error: cannot initialize a variable of type 'void *' with an lvalue of type 'void ()'
void* v = f;
^ ~
foo.c:3:5: error: cannot initialize a variable of type 'int' with an lvalue of type 'void ()'
int i = f;
^ ~
2 errors generated.
答案 2 :(得分:0)
v
和i
的初始化都是非法的。
但是,有些编译器允许从函数指针转换为void*
作为编译器扩展。
尝试使用你的警告进行编译(正如你应该习惯的那样),你也可能会在void* v = f;
行上收到警告。
存储指向函数f
的指针的正确方法是
void (*p)() = f;
答案 3 :(得分:0)
如果你真的想把指针的基础位置放到int
,你可以试试这个:
typedef union _UPTRINT
{
void *ptr;
int i;
} UPTRINT;
然后将函数指针指向UPTRINT::ptr
并将其作为i
访问(假设指针和ints
在您的平台上的大小相同;请调整i
的类型如有必要)。