[英]Strange behavior in casting of function pointers in C++
I have recently encountered a behavior in C++ regarding function pointers, that I can't fully understand. 我最近在C ++中遇到了关于函数指针的行为,我无法完全理解。 I asked Google for help as well as some of my more experienced colleagues, but even they couldn't help.
我向谷歌寻求帮助以及一些经验丰富的同事,但即使他们也无能为力。
The following code showcases this mystique behavior: 以下代码展示了这种神秘行为:
class MyClass{
private:
int i;
public:
MyClass(): i(0) {}
MyClass(int i): i(i) {}
void PrintText() const { std::cout << "some text " << std::endl;}
};
typedef void (*MyFunction) (void*);
void func(MyClass& mc){
mc.PrintText();
}
int main(){
void* v_mc = new MyClass;
MyFunction f = (MyFunction) func; //It works!
f(v_mc); //It works correctly!!!
return 0;
}
So, first I define a simple class that will be used later (especially, it's member method PrintText
). 所以,首先我定义一个稍后将使用的简单类(特别是它的成员方法
PrintText
)。 Then, I define name object void (*) (void*)
as MyFunction
- a pointer to function that has one void*
parameter and doesn't return a value. 然后,我将名称对象
void (*) (void*)
为MyFunction
- 指向具有一个void*
参数且不返回值的函数的指针。
After that, I define function func()
that accepts a reference to MyClass
object and calls its method PrintText
. 之后,我定义了函数
func()
,它接受对MyClass
对象的引用并调用其方法PrintText
。
And finally, magic happens in main function. 最后,魔术发生在主要功能上。 I dynamically allocate memory for new
MyClass
object casting the returned pointer to void*
. 我为新的
MyClass
对象动态分配内存,将返回的指针强制转换为void*
。 Then, I cast pointer to func()
function to MyFunction
pointer - I didn't expect this to compile at all but it does. 然后,我将指向
func()
函数的指针转换为MyFunction
指针 - 我没想到它会完全编译,但确实如此。
And finally, I call this new object with a void*
argument even though underlying function ( func()
) accepts reference to MyClass
object. 最后,我使用
void*
参数调用这个新对象,即使底层函数( func()
)接受对MyClass
对象的引用。 And everything works correctly! 一切正常!
I tried compiling this code with both Visual Studio 2010 (Windows) and XCode 5 (OSX) and it works in the same manner - no warnings are reported whatsoever. 我尝试使用Visual Studio 2010(Windows)和XCode 5(OSX)编译此代码,它以相同的方式工作 - 不报告任何警告。 I imagine the reason why this works is that C++ references are actually implemented as pointers behind the scenes but this is not an explanation.
我想这就是为什么它的工作原理是C ++引用实际上是作为幕后指针实现的,但这不是解释。
I hope someone can explain this behavior. 我希望有人可以解释这种行为。
The formal explanation is simple: undefined behaviour is undefined. 形式化的解释很简单: 未定义的行为未定义。 When you call a function through a pointer to a different function type, it's undefined behaviour and the program can legally do anything (crash, appear to work, order pizza online ... anyting goes).
当您通过指向不同函数类型的指针调用函数时,它是未定义的行为,程序可以合法地执行任何操作(崩溃,似乎工作,在线订购披萨......任何进展)。
You can try reasoning about why the behaviour you're experiencing happens. 您可以尝试推理您遇到的行为发生的原因。 It's probably a combination of one or more of these factors:
它可能是以下一个或多个因素的组合:
PrintText()
doesn't access *this
at all, the compiler can effectively ignore the value of mc
altogether and just call the PrintText()
function inside func
. PrintText()
根本不访问*this
,编译器可以完全有效地忽略mc
的值,只需在func
调用PrintText()
函数。 However, you must remember that while you're currently experiencing the behaviour you've described on your current platform, compiler version and under this phase of the moon, this could change at any time for no apparent reason whatsoever (such as a change in surrounding code triggering different optimisations). 但是,你必须记住,当你正在经历你在当前平台,编译器版本和月球这个阶段所描述的行为时,这可能在任何时候都没有明显的原因(例如改变)周围代码触发不同的优化)。 Remember that undefined behaviour is simply undefined.
请记住,未定义的行为是未定义的。
As to why you can cast &func
to MyFunction
- the standard explicitly allows that (with a reinterpret_cast
, to which the C-style cast translates in this context). 至于为什么你可以将
&func
为MyFunction
- 标准明确允许(使用reinterpret_cast
- reinterpret_cast
,C风格的强制转换在此上下文中转换)。 You can legally cast a pointer to function to any other pointer to function type. 您可以合法地将指向函数的指针强制转换为任何其他指向函数类型的指针。 However, pretty much the only thing you can legally do with it is move it around or cast it back to the original type.
但是,你可以合法地做的唯一事情就是移动它或将其转换回原始类型。 As I said above, if you call through a function pointer of the wrong type, it's undefined behaviour.
如上所述,如果通过错误类型的函数指针调用,则它是未定义的行为。
I hope someone can explain this behavior.
我希望有人可以解释这种行为。
The behaviour is undefined. 行为未定义。
MyFunction f = (MyFunction) func; //It works!
It "works" because you use c-style cast which has the same effect as reinterpret_cast
in this case I think. 它“有效”,因为你使用c-style
reinterpret_cast
在这种情况下我认为与reinterpret_cast
具有相同的效果。 If you had used static_cast
or simply not cast at all, the compiler would have warned of your mistake and failed. 如果你曾经使用过
static_cast
或根本就没有使用,那么编译器会警告你的错误并且失败了。 When you call the wrongly interpreted function pointer, you get undefined behaviour. 当您调用错误解释的函数指针时,您将获得未定义的行为。
It's only by chance that it works. 这只是偶然的机会。 Compilers are not guaranteed to make it work.
编译器不保证能够正常工作。 Behind the scenes, your compiler is treating the reference as a pointer, so your alternative function signature just happens to work.
在幕后,您的编译器将引用视为指针,因此您的替代函数签名恰好起作用。
I'm sorry, to me isn't clear why you call this a strange behavior, I don't see a undefined behavior that depends on moon cycle here, is the way to use function pointers in C. 对不起,对我来说不清楚为什么你称之为奇怪的行为,我没有看到这里依赖于月亮周期的未定义行为,是在C中使用函数指针的方法。
Adding some debug output you may see that the pointer to the object remain the same in all the calls. 添加一些调试输出,您可能会看到指向对象的指针在所有调用中保持不变。
void PrintText() const { std::cout << "some text " << this << std::endl;}
^^^^
void func(MyClass& mc){
std::cout << (void *)&mc << std::endl;
^^^
void *v_mc = new MyClass;
std::cout << (void *)v_mc << std::endl;
^^^^
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.