我可以安全地转换为返回 void 的函数吗?
Can I safely cast to a function returning void?
在采用不同参数或 return 不同类型的函数类型之间进行转换是不安全的,原因很明显。
(对我而言)不明显的是,转换为 return 类型为 void(并且参数类型相同)的函数指针类型是否应该安全。
是否有一种机制可以安全地将 int (*)()
转换为 void (*)()
? static_cast
在这里失败了。 reinterpret_cast
有效,但不安全。
有安全的方法吗?
std::function<void()>(funcReturningInt)
似乎成功了,但我似乎无法通过它的迷宫实现来了解如何实现。
根据标准,没有安全的转换
[expr.reinterpret.cast]/6 A function pointer can be explicitly converted to a function pointer of a different type. [ Note: The effect of calling a function through a pointer to a function type (11.3.5) that is not the same as the type used in the definition of the function is undefined. —end note ] Except that converting a prvalue of type “pointer to T1
” to the type “pointer to T2
” (where T1
and T2
are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified.
希望对您有所帮助。
没有安全的演员表。
另一个答案给出了c++标准的答案,这里我想实际解释一下为什么会这样。
有不同的方法来处理 return 值,C/C++ 没有定义或限制如何处理 return 值。它们在 ABI 中定义。
在 X86 ABI 中定义了几个调用约定,如 cdecl
、stdcall
或 thiscall
。不同的调用约定以不同方式处理 return 值,这里最相关的事实是 return 值存储在哪里。
如果 return 值存储在堆栈中,调用者必须在检索 return 值后调整堆栈指针。在这种情况下,如果您将 return 值转换为 void,则调用者将无法调整堆栈指针,一般情况下堆栈已损坏,这通常会导致崩溃。
如果 return 值存储在寄存器中,调用者可能会假设这些寄存器在调用函数时没有被修改 returning void,但如果没有,这些寄存器可能被调用者修改。不一致也可能导致崩溃。
如果您坚持使用类型转换,只需确保选择 return 值不影响的正确调用约定即可。
正如其他人指出的那样,强制转换并不安全。 std::function
是不必要的。如果您想将函数传递给期望指向 void 函数的指针并忽略 return 结果,您可以使用 lambda 轻松地做到这一点:
int foo();
auto gimme_gimme_a_function_after_midnight(void (*f)() )
{
f();
}
auto test()
{
gimme_gimme_a_function_after_midnight([]() { foo(); });
}
lambda 只调用函数并忽略 returned 值。而且因为它没有捕获,所以它可以隐式转换为函数指针。
如果函数具有易于修改的参数。
为了完整起见,std::function 是通过模板化构造函数实现的。模板化构造函数有效地为每个请求存储的签名类型创建一个静态签名适配器函数,并保留一个指向存储函数的空指针和一个指向适配器函数的函数指针。
在调用时,它使用 void 指针调用适配器函数并将其重新转换回原始类型。
在采用不同参数或 return 不同类型的函数类型之间进行转换是不安全的,原因很明显。
(对我而言)不明显的是,转换为 return 类型为 void(并且参数类型相同)的函数指针类型是否应该安全。
是否有一种机制可以安全地将 int (*)()
转换为 void (*)()
? static_cast
在这里失败了。 reinterpret_cast
有效,但不安全。
有安全的方法吗?
std::function<void()>(funcReturningInt)
似乎成功了,但我似乎无法通过它的迷宫实现来了解如何实现。
根据标准,没有安全的转换
[expr.reinterpret.cast]/6 A function pointer can be explicitly converted to a function pointer of a different type. [ Note: The effect of calling a function through a pointer to a function type (11.3.5) that is not the same as the type used in the definition of the function is undefined. —end note ] Except that converting a prvalue of type “pointer to
T1
” to the type “pointer toT2
” (whereT1
andT2
are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified.
希望对您有所帮助。
没有安全的演员表。
另一个答案给出了c++标准的答案,这里我想实际解释一下为什么会这样。
有不同的方法来处理 return 值,C/C++ 没有定义或限制如何处理 return 值。它们在 ABI 中定义。
在 X86 ABI 中定义了几个调用约定,如 cdecl
、stdcall
或 thiscall
。不同的调用约定以不同方式处理 return 值,这里最相关的事实是 return 值存储在哪里。
如果 return 值存储在堆栈中,调用者必须在检索 return 值后调整堆栈指针。在这种情况下,如果您将 return 值转换为 void,则调用者将无法调整堆栈指针,一般情况下堆栈已损坏,这通常会导致崩溃。
如果 return 值存储在寄存器中,调用者可能会假设这些寄存器在调用函数时没有被修改 returning void,但如果没有,这些寄存器可能被调用者修改。不一致也可能导致崩溃。
如果您坚持使用类型转换,只需确保选择 return 值不影响的正确调用约定即可。
正如其他人指出的那样,强制转换并不安全。 std::function
是不必要的。如果您想将函数传递给期望指向 void 函数的指针并忽略 return 结果,您可以使用 lambda 轻松地做到这一点:
int foo();
auto gimme_gimme_a_function_after_midnight(void (*f)() )
{
f();
}
auto test()
{
gimme_gimme_a_function_after_midnight([]() { foo(); });
}
lambda 只调用函数并忽略 returned 值。而且因为它没有捕获,所以它可以隐式转换为函数指针。
如果函数具有易于修改的参数。
为了完整起见,std::function 是通过模板化构造函数实现的。模板化构造函数有效地为每个请求存储的签名类型创建一个静态签名适配器函数,并保留一个指向存储函数的空指针和一个指向适配器函数的函数指针。
在调用时,它使用 void 指针调用适配器函数并将其重新转换回原始类型。