Soosh
Soosh

Reputation: 812

function pointer to dynamic library in two different ways

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

Can somebody explains how the second one works? Its a little bit confusing!

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


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

Upvotes: 4

Views: 1697

Answers (3)

alexsh
alexsh

Reputation: 1141

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 may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

(**void), as well as &fptr are pointers to objects (since &fptr is a pointer to a pointer to a function), so the cast in your second expression is explicitly allowed by the statement above. 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 not allowed by the standard as you pointed out.

Upvotes: 1

7heo.tk
7heo.tk

Reputation: 1401

On the first line (of the second code paste) declares a function pointer (I imagine that you know that).

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

So the second line can also be read as:

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

Otherwise said: instead of casting the function result as int (*)(int), and affecting the given result to fptr; it casts a pointer on fptr (or it casts fptr's address: a pointer on a pointer) as a void**. Then it dereferences this pointer, effectively giving fptr (the same as the original one, but without the int (*)(int) type), which then gets the result of the dlsym call. It's just a way to 'trick' the compiler into not triggering warnings/errors about a type mismatch. Please also note that even if the syntax you chose is a matter of taste, it's something you should fully understand before you use it in any program you release.

I hope it helps ;)

Upvotes: 3

Medinoc
Medinoc

Reputation: 6608

The difference is the same as the one between:

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

and

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

The first is a regular cast 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 casts between function pointers and regular pointers) doesn't even compile.

The second is a raw bitwise copy, which the compiler will always accept but bypasses any conversion and may lead to writing a variable into another variable of different size. Can be highly dangerous, especially with function pointers.

Upvotes: 2

Related Questions