Consider following program:
#include <iostream>
void f(void* a)
{
std::cout<<"(void*)fun is called\n";
std::cout<<*(int*)a<<'\n';
}
int main()
{
int a=9;
void* b=(int*)&a;
f(b);
return 0;
}
If I change the function call statement like this:
f(&b);
It still compiles fine & crashes at runtime. Why? What is the reason? Should I not get the compile time error? Because the correct way to call the function is f(b). right? Also, why it is allowed to pass NULL to a function whose parameter is of type (void*)?
Please correct me If I am missing something or understanding something incorrectly.
It still compiles fine & crashes at runtime. Why? What is the reason?
Because void* is a technique for removing all type-safety and type checking.
Should I not get the compile time error?
By using void* instead of the correct pointer type int*, you are expressly telling the compiler not to tell you if you are using a type incorrectly or in an undefined way.
Because the correct way to call the function is f(b). right?
That's where your function declaration and contents disagree.
std::cout<<"(void*)fun is called\n";
std::cout<<*(int*)a<<'\n';
The contents above imply that a pointer to int should be passed:
void f(void* a)
This declaration implies some pointer should be passed, and no other restrictions are made.
void* can capture any type of pointers, there is no exception to void**
Ok.
As requested.
Do not use void pointers unless it you cannot think of any other way around it.
And the go to bed and think again.
Void pointers enables the programmer to forget about types. This means that the compile can give up on simple checks. This also in my mind means that the programmer has lost the plot.
Downvote me if you wish.
Using types have the luxury that the compiler can check things out for you. E.g. how things are related. How to treat that object.
But using a void pointer you are very much on your own. Good luck
You'll not get a compile time error because f(&b) calls f and passes the address of b as a parameter which is then casted into a void*. You get a runtime error because then, you are trying to cast a pointer to an integer as an integer.
But yes, as others have stated, doing this a very bad.
First
You can have a void* point to void**. Your code is one of the many examples showing how dangerous void* pointers can be.
Second
You should for type conversion use:
void* b = static_cast<int*>(&a);
instead of the c style conversion you are using:
void*b = (int*)&a;
If I change the function call statement like this:
f(&b);
It still compiles fine & crashes at runtime. Why?
Your function f(void*) will accept a pointer to any type, without complaint. Any pointer quietly converts to a void pointer. A pointer to a pointer is still a pointer. So your second case does indeed compile just fine. And then it crashes. Maybe.
In the first case, you converted from a pointer to int to a pointer to void back to a pointer to int. Those round trip conversions through void* (and also through char*) must work. In the second case, you converted from a void** to a void* to an int*. Now you're invoking undefined behavior. Anything goes. On my computer, my compiler, your code runs just fine. It prints garbage. I was quite sure that your code wouldn't erase my hard drive, but it could. Anything goes with undefined behavior. Don't invoke undefined behavior.
The reason for supporting void* is historic. There is a lot of old C and C++ code that use void pointers. The only reason to write new C++ code that uses void pointers is if you need to interact with one of those old functions that use void pointers.
I found myself here because I am working on a homework assignment that requests the same functionality. After combining each comment, this is what I came up with.
// A function that accepts a void pointer
void f(void* a)
{
std::cout<<"(void*)fun is called\n";
std::cout<< "value for a: " << *(int*)a << '\n';
}
int main() {
int a = 9;
void* c = static_cast<int*>(&a);
int b = 3;
f(&b);
f(c);
}
Related
Just want to understand the following code:
Why we use option (1) other than option (2)? I don't know what's the use of (void**) here? really confused.
Class Handle{
private:
int unique_id;
int (*m_handle)(int arg1, int arg2);
public:
bool init(){
*(void **)(&m_handle) = dlsym(dlopen(./haldle_lib.so, RTLD_NOW), "custom_func"); // (1)
//m_handle = (decltype(m_handle))dlsym(dlopen(./haldle_lib.so, RTLD_NOW), "custom_func");//(2)
}
}
add reference https://www.tldp.org/HOWTO/pdf/C++-dlopen.pdf
Converting a pointer of type void* to a function pointer is not allowed. In other words, from C++ point of view, function pointers and object pointers are not the same thing.
In option 1, the trick is that you first get the address of the function pointer (&m_handle). Then you pretend that this pointer (i.e. &m_handle) points to an ordinary object pointer (of type void*) and not to a pointer to a function pointer. Using this pointer ((void **)(&m_handle)), you use operator* to deference it and and write the value returned by dlsym(..) into the function pointer.
The code should be:
void *m = dlsym(....);
m_handle = reinterpret_cast<decltype(m_handle)>(m);
The second line is conditionally-supported in C++ so we presume the code is being built by a compiler that does support converting void * to function pointer.
The original code causes undefined behaviour due to strict aliasing violation, it tries to pretend that m_handle is actually a void * object when it is not .
Being undefined behaviour, the original code may or may not appear to work the same as the correct version . It is certainly not a good idea to rely on undefined behaviour.
I have recently encountered a behavior in C++ regarding function pointers, that I can't fully understand. 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). Then, I define name object void (*) (void*) as MyFunction - a pointer to function that has one void* parameter and doesn't return a value.
After that, I define function func() that accepts a reference to MyClass object and calls its method PrintText.
And finally, magic happens in main function. I dynamically allocate memory for new MyClass object casting the returned pointer to void*. Then, I cast pointer to func() function to MyFunction pointer - I didn't expect this to compile at all but it does.
And finally, I call this new object with a void* argument even though underlying function (func()) accepts reference to MyClass object. 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. 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.
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:
Your compiler internally implements references as pointers.
On your platform, all pointers have the same size and binary representation.
Since 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.
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). 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. If you had used static_cast or simply not cast at all, the compiler would have warned of your mistake and failed. 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.
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;
^^^^
So in "the c++ programming language, 4th edition", there's a paragraph I don't understand about conversion of pointer-to-function types. Here is some of the code sample.
using P1 = int(*)(int*);
using P2 = void(*)(void);
void f(P1 pf) {
P2 pf2 = reinterpret_cast<P2>(pf);
pf2(); // likely serious problem
// other codes
}
When I run this it crashed.
I'm not sure if I am right, but I initially think the "likely serious problem" comment is when pf got casted to P2 in pf2, I think pf2 is not pointing to anything? Because when I created a function that matches P2's type and point pf2 to it, it didn't crash and runs normally.
After the code, I read this:
We need the nastiest of casts, reinterpret_cast, to do conversion of pointer-to-function types. The reason is that the result of using a pointer to function of the wrong type is so unpredictable and system-dependent. For example, in the example above, the called function may write to the object pointed to by its argument, but the call pf2() didn’t supply any argument!
Now I'm completely lost starting from "For example, in the example above" part:
"may write to the object pointed to by its argument" //what object is it exactly?
"but the call pf2() didn’t supply any argument!" //"using P2 = void(*)(void);" doesn't really need an arguement does it?
I think I'm missing something here. Can someone explain this?
For example, in the example above, the called function may write to the object pointed to by its argument (...)
pf is a pointer to a function like this:
int foo(int* intPtr)
{
// ...
}
So it could be implemented to write to its argument:
int foo(int* intPtr)
{
*intPtr = 42; // writing to the address given as argument
return 0;
}
(...) but the call pf2() didn’t supply any argument!
When you call foo through its cast to type P2, it will be called without arguments, so it is unclear what intPtr will be:
P2 pf2 = reinterpret_cast<P2>(pf);
pf2(); // no argument given here, although pf2 really is foo() and expects one!
Writing to it will most likely corrupt something.
Moreover, compilers usually implement calls to functions that return something by reserving space for the return value first, that will then be filled by the function call. When you call a P1 using the signature of P2, the call to P2 won't reserve space (as the return value is void) and the actual call will write an int somewhere it should not, which is another source for corruption.
Now I'm completely lost starting from "For example, in the example
above" part:
"may write to the object pointed to by its argument" //what object is
it exactly?
P1 is a function expecting a non-const pointer-to-int argument. That means it very well may write to the int referenced in its argument.
"but the call pf2() didn’t supply any argument!" //"using P2 =
void(*)(void);" doesn't really need an arguement does it?
When you call the function through another function pointer type passing no argument, the expectations of the called function aren't met. It may try to interpret whatever is on the stack as an int pointer and write to it, causing undefined behavior.
This does fail, but not necessarily in the way one might expect.
The implementation of a function pointer is left up to the compiler (undefined). Even the size of a function pointer can be bigger than a void*.
What is guaranteed about the size of a function pointer?
There is no guarentees about anything in the value of the function pointer. In fact, the only even guarentee that the comparison operators will work between function pointers of the same type.
Comparing function pointers
The standard does provide that function pointers can store the values of other function types.
Casting the function pointer to another type undefined behavior, meaning the compiler can do whatever it wants. Whether or not you supply the argument really doesn't matter, and how that would fail depends on the calling convention of the system. As far as your concerned, it could allow "demons to fly out of your nose".
Casting a function pointer to another type
So that brings us back to the statement by the author:
We need the nastiest of casts, reinterpret_cast, to do conversion of pointer-to-function types. The reason is that the result of using a pointer to function of the wrong type is so unpredictable and system-dependent. For example, in the example above, the called function may write to the object pointed to by its argument, but the call pf2() didn’t supply any argument!
That is trying to make the point that with no argument specified, if the function writes the output, it will write to some uninitialized state. Basically, if you look at the function as
int foo(int* arg) {*arg=10;}
if you didn't initialize arg, the author says you could be writing anywhere. But again, there is no guarentee that this even matters. The system could store functions with the footprint int (*)(int*) and void(*)(void) in completely different memory space, in which case instead of the above problem you'd have a jump into a random location in the program. Undefined behavior is just that: undefined.
Just don't do it man.
I am very new to C++. Currently I am reviewing a source code where I saw some typecasting, but I didn't understand it.
Here is the code.
struct str {
char *a;
int b;
};
class F {
public:
char* val;
};
F f1;
Can anyone explain the below Assignement Please.or is that typecasting valid??
str* ptr = (str*) f1->val;
Can anyone explain the below Assignement Please.
It means "pretend that the val pointer points to an object of type str, even though it's declared to point to a completely different type char; give me that pointer and trust that I know what I'm doing".
That's assuming that the real code either declares F * f1;, or accesses it as f1.val; the code you've posted won't compile.
or is that typecasting valid??
If the pointer really does point to an object of the correct type, then it's valid; otherwise, using the pointer will cause the program to fail in all sorts of catastrophic ways.
Typecasting is something that should very rarely be necessary. If you really do need it, you should never (as in absolutely never, under any circumstances) use that C-style cast; it means "force the conversion with no checks whatsoever, as long as there's some way to do it, even if it makes absolutely no sense". Use static_cast or dynamic_cast when you can, and reinterpret_cast or const_cast when you're doing something really dodgy. And don't use any of them unless you know what you're doing, and have a very good reason for circumventing the type system.
I'm curious why C++ does not define void via :
typedef struct { } void;
I.e. what is the value in a type that cannot be instantiated, even if that installation must produce no code?
If we use gcc -O3 -S, then both the following produce identical assembler :
int main() { return 0; }
and
template <class T> T f(T a) { }
typedef struct { } moo;
int main() { moo a; f(a); return 0; }
This makes perfect sense. A struct { } simply takes an empty value, easy enough to optimize away. In fact, the strange part is that they produce different code without the -O3.
You cannot however pull this same trick with simply typedef void moo because void cannot assume any value, not even an empty one. Does this distinction have any utility?
There are various other strongly typed languages like Haskell, and presumably the MLs, that have a value for their void type, but offer no valueless types overtly, although some posses native pointer types, which act like void *.
I see the rationale for void being unable to be instantiated coming from the C roots of C++. In the old gory days, type safety wasn't that big a deal and void*s were constantly passed around. However, you could always be looking at code that does not literally say void* (due to typedefs, macros, and in C++, templates) but still means it.
It is a tiny bit of safety if you cannot dereference a void* but have to cast it to a pointer to a proper type, first. Whether you accomplish that by using an incomplete type as Ben Voigt suggests, or if you use the built-in void type doesn't matter. You're protected from incorrectly guessing that you are dealing with a type, which you are not.
Yes, void introduces annoying special cases, especially when designing templates. But it's a good thing (i.e. intentional) that the compiler doesn't silently accept attempts to instantiate void.
Because that wouldn't make void an incomplete type, now would it?
Try your example code again with:
struct x; // incomplete
typedef x moo;
Why should void be an incomplete type?
There are many reasons.
The simplest is this: moo FuncName(...) must still return something. Whether it is a neutral value, whether it is the "not a value value", or whatever; it still must say return value;, where value is some actual value. It must say return moo();.
Why write a function that technically returns something, when it isn't actually returning something? The compiler can't optimize the return out, because it's returning a value of a complete type. The caller might actually use it.
C++ isn't all templates, you know. The compiler doesn't necessarily have the knowledge to throw everything away. It often has to perform in-function optimizations that have no knowledge of the external use of that code.
void in this case means "I don't return anything." There is a fundamental difference between that and "I return a meaningless value." It is legal to do this:
moo FuncName(...) { return moo(); }
moo x = FuncName(...);
This is at best misleading. A cursory scan suggests that a value is being returned and stored. The identifier x now has a value and can be used for something.
Whereas this:
void FuncName(...) {}
void x = FuncName(...);
is a compiler error. So is this:
void FuncName(...) {}
moo x = FuncName(...);
It's clear what's going on: FuncName has no return value.
Even if you were designing C++ from scratch, with no hold-overs from C, you would still need some keyword to indicate the difference between a function that returns a value and one that does not.
Furthermore, void* is special in part because void is not a complete type. Because the standard mandates that it isn't a complete type, the concept of a void* can mean "pointer to untyped memory." This has specialized casting semantics. Pointers to typed memory can be implicitly cast to untyped memory. Pointers to untyped memory can be explicitly cast back to the typed pointer that it used to be.
If you used moo* instead, then the semantics get weird. You have a pointer to typed memory. Currently, C++ defines casting between unrelated typed pointers (except for certain special cases) to be undefined behavior. Now the standard has to add another exception for the moo type. It has to say what happens when you do this:
moo *m = new moo;
*moo;
With void, this is a compiler error. What is it with moo? It's still useless and meaningless, but the compiler has to allow it.
To be honest, I would say that the better question would be "Why should void be a complete type?"