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

问题描述 投票:0回答:4

考虑以下代码:

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

为什么将函数地址存储到

int
变量中会给我一个错误

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

但是对于

void*
变量则不然?

c function-address
4个回答
3
投票

当我编译这个时,我得到:

$ 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.

3
投票
  • 在文件范围(“全局”)声明的变量具有静态存储持续时间。

    所有具有静态存储持续时间的变量必须初始化为编译时常量。在 C 中,其他变量(甚至不是

    const
    变量)不计为编译时常量,因此会出现错误。

  • 此外,您不能将指针分配给整数,这样做是无效的 C。您必须首先通过强制转换将指针手动转换为整数类型。

  • 此外,演员阵容

    void* v = f;
    也没有明确定义。 C 标准仅指定
    void*
    和指向对象类型的指针之间的转换。


现在你应该做的是获取函数的地址:

#include <stdint.h>

uintptr_t i = (uintptr_t) f;

int main (void)
{ ...

uintptr_t
保证足够大以包含任何指针的地址。


0
投票

v
i
的初始化都是非法的。

但是,某些编译器允许从函数指针转换为

void*
作为编译器扩展。

尝试在编译时打开警告(按照习惯),您也可能会在

void* v = f;
行收到警告。

存储指向函数

f
的指针的正确方法是

void (*p)() = f;

0
投票

如果您确实想将指针的底层位放入

int
中,您可以尝试以下操作:

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

然后将函数指针分配给

UPTRINT::ptr
并以
i
的形式访问它(假设指针和
ints
在您的平台上大小相同;根据需要调整
i
的类型)。

© www.soinside.com 2019 - 2024. All rights reserved.