c++ - 将函数指针转换为 void(*)(),然后重新转换为原始类型

标签 c++ pointers c++11 function-pointers

这个问题是为了测试目的,仅此而已。

我目前正在尝试存储具有不同数量参数的函数指针(并且这些参数可以具有不同类型)。

基本上,我用 C++11 编写了以下代码片段:

#include <functional>
#include <iostream>

void fct(int nb, char c, int nb2, int nb3) {
  std::cout << nb << c << nb2 << nb3 << std::endl;
}

template <typename... Args>
void call(void (*f)(), Args... args) {
  (reinterpret_cast<void(*)(Args...)>(f))(args...);
}

int main(void) {
  call(reinterpret_cast<void(*)()>(&fct), 42, 'c', 19, 94);
}

我将 void(*)(int, char, int, int) 函数指针转换为通用 void(*)() 函数指针。然后,通过使用可变模板参数,我只需将函数指针重铸为其原始类型,并使用一些参数调用该函数。

此代码编译并运行。大多数时候,它显示了良好的值(value)。然而,这段代码在 Mac OS 下给我一些 Valgrind 错误(关于未初始化的值),它有时会显示一些意想不到的垃圾。

==52187== Conditional jump or move depends on uninitialised value(s)
==52187==    at 0x1004E4C3F: _platform_memchr$VARIANT$Haswell (in /usr/lib/system/libsystem_platform.dylib)
==52187==    by 0x1002D8B96: __sfvwrite (in /usr/lib/system/libsystem_c.dylib)
==52187==    by 0x1002D90AA: fwrite (in /usr/lib/system/libsystem_c.dylib)
==52187==    by 0x100025D29: std::__1::__stdoutbuf<char>::overflow(int) (in /usr/lib/libc++.1.dylib)
==52187==    by 0x10001B91C: std::__1::basic_streambuf<char, std::__1::char_traits<char> >::xsputn(char const*, long) (in /usr/lib/libc++.1.dylib)
==52187==    by 0x10003BDB0: std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> > std::__1::__pad_and_output<char, std::__1::char_traits<char> >(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> >, char const*, char const*, char const*, std::__1::ios_base&, char) (in /usr/lib/libc++.1.dylib)
==52187==    by 0x10003B9A7: std::__1::num_put<char, std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> > >::do_put(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char> >, std::__1::ios_base&, char, long) const (in /usr/lib/libc++.1.dylib)
==52187==    by 0x1000217A4: std::__1::basic_ostream<char, std::__1::char_traits<char> >::operator<<(int) (in /usr/lib/libc++.1.dylib)
==52187==    by 0x1000011E8: fct(int, char, int, int) (in ./a.out)
==52187==    by 0x1000013C2: void call<int, char, int, int>(void (*)(), int, char, int, int) (in ./a.out)
==52187==    by 0x100001257: main (in ./a.out)

我觉得这很好奇,因为当我调用该函数时,我已将函数指针重铸为其原始类型。我认为这类似于将数据类型转换为 void*,然后将其重新转换为原始数据类型。

我的代码有什么问题?我们不能将函数指针转换为 void(*)() 指针,然后将此指针重新转换为原始函数指针签名吗?

如果没有,是否有其他方法可以实现?我对 std::bind 不感兴趣,这不是我想要的。

最佳答案

冒着风险猜测你做了什么让它失败......

#include <functional>
#include <iostream>

void fct(int nb, char c, int nb2, std::string nb3) {
  std::cout << nb << c << nb2 << nb3 << std::endl;
}

template <typename... Args>
void call(void (*f)(), Args... args) {
  (reinterpret_cast<void(*)(Args...)>(f))(args...);
}

int main(void) {
  call(reinterpret_cast<void(*)()>(&fct), 42, 'c', 19, "foobar");
}

这将失败,因为“foobar”永远不会被转换为 std::string ...编译器如何知道它是否通过 Args...

我不确定 std::string 是如何被调用者推送到调用堆栈的(字符串引用将作为指针推送),但我怀疑它不仅仅是只是一个指向 char* 的指针。当被调用者弹出指向 char* 的指针并期待整个 string 成员时,它吓坏了。

我想如果你改成

void fct(int nb, char c, int nb2, char* nb3)

call(reinterpret_cast<void(*)()>(&fct), 42, 'c', 19, std::string("foobar"));

那么它可能会起作用。

关于c++ - 将函数指针转换为 void(*)(),然后重新转换为原始类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31149413/

相关文章:

c++ - 使用 g++ -m32 选项编译 C++

c++ - 如何设计我的类(class)?

c++ - 通过模板传递成员函数指针

c++ - 如何确定更大类型的 decltype 表达式

python - 关于通过(unix-)套接字发送/接收大量数据的另一个困惑

c++ - 静态断言失败 : variant must have no reference alternative

c++ - 如何读取与另一个线程共享的 std::queue?

C - 内存分配问题 - 需要解释

C++ 通过引用多次传递指针然后修改它。我怎样才能让它发挥作用?

c - C 中结构体指针的问题