将函数地址存储到全局变量中

时间:2016-11-29 15:39:59

标签: c

请考虑以下代码:

void f() {};
void* v = f;
int i = f;
int main() { }

为什么将函数地址存储到int变量中会给我一个error

  

错误:初始化元素不是编译时常量

但是对于void*变量没有?

4 个答案:

答案 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)

vi的初始化都是非法的。

但是,有些编译器允许从函数指针转换为void*作为编译器扩展。

尝试使用你的警告进行编译(正如你应该习惯的那样),你也可能会在void* v = f;行上收到警告。

存储指向函数f的指针的正确方法是

void (*p)() = f;

答案 3 :(得分:0)

如果你真的想把指针的基础位置放到int,你可以试试这个:

typedef union _UPTRINT
{
    void *ptr;
    int i;
} UPTRINT;

然后将函数指针指向UPTRINT::ptr并将其作为i访问(假设指针和ints在您的平台上的大小相同;请调整i的类型如有必要)。