Why are function pointers and data pointers incomp

2019-01-02 17:49发布

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-02 18:09

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

查看更多
梦醉为红颜
3楼-- · 2019-01-02 18:11

Some computers have (had) separate address spaces for code and data. On such hardware it just doesn't work.

The language is designed not only for current desktop applications, but to allow it to be implemented on a large set of hardware.


It seems like the C language committee never intended void* to be a pointer to function, they just wanted a generic pointer to objects.

The C99 Rationale says:

6.3.2.3 Pointers
C has now been implemented on a wide range of architectures. While some of these architectures feature uniform pointers which are the size of some integer type, maximally portable code cannot assume any necessary correspondence between different pointer types and the integer types. On some implementations, pointers can even be wider than any integer type.

The use of void* (“pointer to void”) as a generic object pointer type is an invention of the C89 Committee. Adoption of this type was stimulated by the desire to specify function prototype arguments that either quietly convert arbitrary pointers (as in fread) or complain if the argument type does not exactly match (as in strcmp). Nothing is said about pointers to functions, which may be incommensurate with object pointers and/or integers.

Note Nothing is said about pointers to functions in the last paragraph. They might be different from other pointers, and the committee is aware of that.

查看更多
无色无味的生活
4楼-- · 2019-01-02 18:12

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-02 18:12

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.

查看更多
其实,你不懂
6楼-- · 2019-01-02 18:14

For those who remember MS-DOS, Windows 3.1 and older the answer is quite easy. All of these used to support several different memory models, with varying combinations of characteristics for code and data pointers.

So for instance for the Compact model (small code, large data):

sizeof(void *) > sizeof(void(*)())

and conversely in the Medium model (large code, small data):

sizeof(void *) < sizeof(void(*)())

In this case you didn't have separate storage for code and date but still couldn't convert between the two pointers (short of using non-standard __near and __far modifiers).

Additionally there's no guarantee that even if the pointers are the same size, that they point to the same thing - in the DOS Small memory model, both code and data used near pointers, but they pointed to different segments. So converting a function pointer to a data pointer wouldn't give you a pointer that had any relationship to the function at all, and hence there was no use for such a conversion.

查看更多
若你有天会懂
7楼-- · 2019-01-02 18:16

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.

查看更多
登录 后发表回答