将函数地址转换为64位整数:未定义/不正常?

时间:2014-10-14 03:51:15

标签: c++ c undefined-behavior

背景:我有一个场景,我必须允许在两个仿函数对象之间进行比较,使用唯一的ID来测试它们是否相等(我不能简单地检查它们的地址是否相同,如函数指针本身不存储在对象中。最初,我有这个想法,只需在0处启动id生成器并无限增加ad:

struct GenerateUniqueID{
    static std::size_t id_count = 0;

    auto operator()() -> std::size_t { return (id_count++); }
};

...但是,由于我每隔几秒就创建了成千上万的这些对象,我实际上设法遇到id_count溢出回0的情况!结果......令人不快。现在,我的第二个想法是,因为这些仿函数显然是函数的包装器,我可以通过将函数指针的地址转换为64位整数来执行比较,并将其存储在类中以进行比较。参见:

//psuedocode
struct Functor{
    std::uint64_t id;

    auto generate_id_from_function_address(function f) -> void {
        id = reinterpret_cast<std::uint64_t>(&f);
    }
};

现在,我的担心很简单:将函数指针转换为64位整数,表现不正常/未定义?在32位架构上?在64位架构上?在两者上?我主要关心的是虚函数,因为我知道对于内联函数,编译器只是创建一个非内联版本,所以那里没有问题。

1 个答案:

答案 0 :(得分:2)

将常规指针(更不用说函数指针)转换为uint64_t是实现定义的,因为指针可能比64位宽。如果您使用uintptr_t(并且存在该类型),则转换是明确定义的。

将函数指针转换为任何整数类型是实现定义的(即使使用uintptr_t),因为函数指针可能比常规指针更宽。像POSIX这样的其他标准明确允许这样做,因此在POSIX下,将函数指针强制转换为void*uintptr_t等数据指针是安全的。

(将指向成员的指针转换为整数,数据指针或常规函数指针是未定义的,并且实际上可能总是失败,因为它们比常规指针大。)

但是,对于您的唯一ID,使用uint64_t代替size_t可能更简单。由于它们的范围很大,基本上不可能通过重复递增uint64_t来溢出它。