Marc Aurele La France <yyy@xxxxxxxxxxx> said:
> On Fri, 12 Apr 2002, Matt Seitz wrote:
> > Any suggestions for improving this idea?
The reason the C standard makes this undefined is because data pointers and
function pointers may have different sizes on some platforms. If you pick
either one for the return type of dlsym(), converting to the other kind of
pointers will lose some significant bits on some platforms. If you want to
make this work on all such platforms, you must make the return type of dlsym
() implementation-defined, and require a typecast.
Of course, you can instead say that you don't care about platforms that have
data pointers smaller than function pointers; dlsym(), as currently defined,
has no chance of working on such platforms anyway.
> Oddly enough, I recently ran into this in my own work. What I ended up
> with is instead of
>
> fptr = (int (*)(int))dlsym(handle, "my_function");
>
> I did
>
> *(void **)(&fptr) = dlsym(handle, "my_function");
>
> ... which is, I'll grant, a little kludgy, but is perfectly legal in
> ANSI or ISO C terms.
A little?
It's only "legal" in the sense that it doesn't require the compiler to issue
a diagnostic; but it is undefined behaviour in ISO C. And it's actually less
portable than the original typecast:
* On a platform where function pointers are smaller than data pointers,
you're clobbering memory outside of the fptr variable. A cast from void* to
a function pointer would just work: yes, it would throw away the extra bits
instead of storing them in some unrelated variable, but if the symbol you
asked for indeed was a function, those extra bits would have all been
insignificant anyway.
* Even if function pointers are the same size as data pointers, their
representation could be different. Imagine a machine that stores function
pointers as "big endian" (segment, then offset) but data pointers as "little
endian" (offset, then segment). A normal typecast would allow the compiler
to swap the segment and the offset; yours doesn't.
|