Functional pointer to a dynamic library in two different ways

The following two values ​​are the same, but the C99 standard leaves casting from void * to the function pointer undefined.

Can someone explain how the second works? This is a bit confusing!

 int (*fptr)(int); fptr = (int (*)(int))dlsym(handle, "my_function"); 


 int (*fptr)(int); *(void **) (&fptr) = dlsym(handle, "my_function"); 
+4
source share
3 answers

The first line (second paste of the code) declares a pointer to the function (I assume you know that).

Now dlsym(3) is the call that void * returns.

Thus, the second line can also be read as:

 *((void **) (&fptr)) = dlsym(handle, "function"); 

Otherwise, it is said: instead of distinguishing the result of the function as int (*)(int) and influencing the given result on fptr; it casts a pointer to fptr (or it gives the address fptr: pointer to a pointer) as void** . He then casts that pointer, effectively giving fptr (the same as the original, but without the int (*)(int) ), which then gets the result of calling dlsym . This is just a way to β€œtrick” the compiler into not triggering warnings / errors about type mismatches. Also note that even if the syntax you choose is a matter of taste, you must fully understand before using it in any program that you have released.

I hope this helps;)

+3
source

The difference is the same as between:

 float f = 3.14; int i = (int)f; 

and

 float f = 3.14; int i = *(int*)&f; 

The first is a regular listing of the value, which in some cases (int ↔ float or back in the 8086 days near pointer ↔ far pointer) causes some conversions; and in some cases (some castings between function pointers and regular pointers) are not even compiled.

The second is a raw bitwise copy, which the compiler always accepts, but bypasses any conversion and can lead to a variable being written to another variable of different sizes. It can be very dangerous, especially with function pointers.

+2
source

The reason the second version is legal is in the following part of the ISO standard:

6.3.2.3 Pointers 1 A pointer to void can be converted to or from a pointer to any type of object. A pointer to any type of object can be converted to a pointer to void and vice versa; The result should compare with the original pointer.

(**void) as well as &fptr are pointers to objects (since & fptr is a pointer to a pointer to a function), so casting in your second expression is explicitly permitted by the above statement. Your first expression is trying to convert a pointer to an object (rather a pointer to void , which is a special case in the standard) to a pointer to a function (which is not an object), which is prohibited by the standard as you indicated.

+1
source

Source: https://habr.com/ru/post/1497827/


All Articles