Why are function pointers and data pointers incomp

2019-01-27 15:37发布

I have read that converting a function pointer to a data pointer and vice versa works on most platforms but is not guaranteed to work. Why is this the case? Shouldn't both be simply addresses into main memory and therefore be compatible?

14条回答
冷血范
2楼-- · 2019-01-27 16:14

C++11 has a solution to the long-standing mismatch between C/C++ and POSIX with regard to dlsym(). One can use reinterpret_cast to convert a function pointer to/from a data pointer so long as the implementation supports this feature.

From the standard, 5.2.10 para. 8, "converting a function pointer to an object pointer type or vice versa is conditionally-supported." 1.3.5 defines "conditionally-supported" as a "program construct that an implementation is not required to support".

查看更多
女痞
3楼-- · 2019-01-27 16:18

Depending on the target architecture, code and data may be stored in fundamentally incompatible, physically distinct areas of memory.

查看更多
Ridiculous、
4楼-- · 2019-01-27 16:18

They can be different types with different space requirements. Assigning to one can irreversibly slice the value of the pointer so that assigning back results in something different.

I believe they can be different types because the standard doesn't want to limit possible implementations that save space when it's not needed or when the size could cause the CPU to have to do extra crap to use it, etc...

查看更多
何必那么认真
5楼-- · 2019-01-27 16:18

Another solution:

Assuming POSIX guarantees function and data pointers to have the same size and representation (I can't find the text for this, but the example OP cited suggests they at least intended to make this requirement), the following should work:

double (*cosine)(double);
void *tmp;
handle = dlopen("libm.so", RTLD_LAZY);
tmp = dlsym(handle, "cos");
memcpy(&cosine, &tmp, sizeof cosine);

This avoids violating the aliasing rules by going through the char [] representation, which is allowed to alias all types.

Yet another approach:

union {
    double (*fptr)(double);
    void *dptr;
} u;
u.dptr = dlsym(handle, "cos");
cosine = u.fptr;

But I would recommend the memcpy approach if you want absolutely 100% correct C.

查看更多
Root(大扎)
6楼-- · 2019-01-27 16:23

On most architectures, pointers to all normal data types have the same representation, so casting between data pointer types is a no-op.

However, it's conceivable that function pointers might require a different representation, perhaps they're larger than other pointers. If void* could hold function pointers, this would mean that void*'s representation would have to be the larger size. And all casts of data pointers to/from void* would have to perform this extra copy.

As someone mentioned, if you need this you can achieve it using a union. But most uses of void* are just for data, so it would be onerous to increase all their memory use just in case a function pointer needs to be stored.

查看更多
Explosion°爆炸
7楼-- · 2019-01-27 16:23

I know that this hasn't been commented on since 2012, but I thought it would be useful to add that I do know an architecture that has very incompatible pointers for data and functions since a call on that architecture checks privilege and carries extra information. No amount of casting will help. It's The Mill.

查看更多
登录 后发表回答