【问题标题】:c++: is it safe to cast pointer to functions?c ++:将指针转换为函数是否安全?
【发布时间】:2012-01-27 15:02:46
【问题描述】:

我想知道将double (*)(double) 转换为double(*)(...) 是否安全,这将用于概括可能具有多个函数指针的代码。

到目前为止,我已经将要传递给函数的所有内容都存储在向量中,我想知道是否有一种方法可以在广义上调用函数(同时传递正确数量的参数)代码?我的意思是这样的:

//while initializing
mFunction = sin;
//later in code
double (*generalized)(...) = mFunction;
for(i=0;i<args.size();i++)
    pusharg(args[i]);
call(generalized);

--编辑--

如果没有使用 c++ 的有效方法,是否可以使用汇编安全地调用函数?

【问题讨论】:

  • 好吧,不是!我试图从“指向函数的指针”转换为“指向具有其他签名的函数的指针”,而他试图将“void *”转换为“函数指针”

标签: c++ assembly casting function-pointers


【解决方案1】:

您不能直接将double(*)(double) 分配给double(*)(...),但您可以reinterpret_cast 它。 §5.2.10[expr.reinterpret.cast]/6 明确允许强制转换,但调用强制转换的函数指针将导致未定义的行为:

函数指针可以显式转换为不同类型的函数指针。

通过指向与函数定义中使用的类型不同的函数类型的指针调用函数的效果是undefined

除了将“指向T1的指针”类型的纯右值转换为“指向T2的指针”类型(其中T1T2是函数类型)并返回其原始类型会产生原始指针值,这种指针转换的结果是未指定的。

很容易看出为什么它会导致 UB — 如果我们调用 generalized(1.0, 2.0, 3.0) 会怎样?这可能会破坏调用堆栈。但是,如果在调用之前将 generalized 转换回 double(*)(double) 就可以了。

【讨论】:

  • 因为它是私有成员,所以我不需要担心可能的程序员错误。所以如果我已经将sin(double) 转换为generalize(double, ...),我只会打电话给generalize(1.0),或者如果它是hypot(double,double),我可以确保只打电话给generalize(1.0,2.0)
  • @Gajet:如果可能的话,最好还是转换回原始类型以避免错误。 ... 可能会更改调用约定(例如,如果您将 float 传递给 ... 参数,它将在调用函数之前转换为 double。)
【解决方案2】:

是的,铸造本身是允许的。但是,用错误的签名来调用它不是。请注意,如果您想要一个通用函数指针,最好使用void (*)(),它就像void* 用于函数指针(但没有隐式转换)。

甚至更好,因为您显然提供了特定参数,因此请使用 std::functionstd::bind(如果您的编译器支持 C++11 库)或它们的 Boost 等效项。

【讨论】:

  • "注意,如果你想要一个泛型函数指针,最好使用void (*)()" 我宁愿使用不能调用的指针,比如void (*)(boost::noncopyable)。跨度>
  • 是否有对我有用的等效汇编代码?
  • @Gajet:我相信你知道,组装是非常不便携的。不过还是有可能的。我实现了我自己的委托类来取乐,因为调用代码基本上变成了几条装配线。但请注意,它非常有问题,可能会导致问题。
【解决方案3】:

使generalized volatile 需要编译器遵循 ABI 规范。由于希望支持未声明的 C 函数,这在大多数 ABI(包括 x86 和 x86-32)上是安全的,如果一个函数通过指向具有固定数量参数的函数的指针而不调用除了可变数量的参数的函数.

【讨论】:

    猜你喜欢
    • 2013-03-17
    • 2011-04-03
    • 1970-01-01
    • 1970-01-01
    • 2019-12-29
    • 1970-01-01
    • 2014-09-22
    • 2012-11-21
    • 2020-11-22
    相关资源
    最近更新 更多