gex*_*ide 128 c c++ pointers function-pointers
我已经读过将函数指针转换为数据指针,反之亦然,但在大多数平台上都可以工作,但不能保证工作.为什么会这样?两者都不应该只是简单地址到主存储器中,因此兼容吗?
Dir*_*ple 169
架构不必将代码和数据存储在同一存储器中.使用哈佛架构,代码和数据存储在完全不同的内存中.大多数体系结构都是Von Neumann体系结构,代码和数据存储在同一个内存中,但C并不仅限于某些类型的体系结构(如果可能的话).
Bo *_*son 37
一些计算机具有(具有)用于代码和数据的单独地址空间.在这样的硬件上它只是不起作用.
该语言不仅适用于当前的桌面应用程序,还允许在大量硬件上实现.
似乎C语言委员会从未打算void*成为函数的指针,他们只是想要一个指向对象的泛型指针.
C99理由说:
6.3.2.3指针
C现已在各种架构上实现.虽然这些体系结构中的一些具有统一指针,这些指针是某种整数类型的大小,但是最大可移植代码不能假设不同指针类型和整数类型之间的任何必要的对应关系.在某些实现中,指针甚至可以比任何整数类型更宽.使用
void*("指向"指针void)作为通用对象指针类型是C89委员会的发明.指定函数原型参数的愿望刺激了这种类型的采用,这些参数要么悄悄地转换任意指针(如fread),要么抱怨如果参数类型不完全匹配(如strcmp).关于函数的指针没有任何说法,这可能与对象指针和/或整数不相称.
注意在最后一段中没有关于函数指针的说法.它们可能与其他指针不同,委员会也知道这一点.
Tom*_*mek 30
对于那些记得MS-DOS,Windows 3.1及更早版本的人来说,答案非常简单.所有这些都用于支持几种不同的内存模型,具有代码和数据指针的不同特征组合.
例如,对于Compact模型(小代码,大数据):
sizeof(void *) > sizeof(void(*)())
Run Code Online (Sandbox Code Playgroud)
相反,在Medium模型中(大代码,小数据):
sizeof(void *) < sizeof(void(*)())
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您没有单独的代码和日期存储空间,但仍然无法在两个指针之间进行转换(使用非标准的__near和__far修饰符).
此外,即使指针大小相同,也无法保证它们指向相同的东西 - 在DOS小内存模型中,指针附近使用的代码和数据,但它们指向不同的段.因此,将函数指针转换为数据指针不会给你一个与函数有任何关系的指针,因此没有用于这样的转换.
Jer*_*fin 23
指向void的指针应该能够容纳指向任何类型数据的指针 - 但不一定是指向函数的指针.有些系统具有用于函数指针比指针数据不同要求(例如,存在与不同的DSP寻址数据与代码,在MS-DOS介质模型用于代码32位指针但对于数据唯一的16位指针) .
Max*_*kin 13
除了这里已经说过的,看看POSIX很有意思dlsym():
ISO C标准不要求指向函数的指针可以来回转换为指向数据的指针.实际上,ISO C标准不要求void*类型的对象可以保存指向函数的指针.但是,支持XSI扩展的实现确实需要void*类型的对象可以保存指向函数的指针.但是,将指向函数的指针转换为指向另一种数据类型(void*除外)的指针的结果仍未定义.请注意,如果尝试从void*指针到函数指针的转换,则需要符合ISO C标准的编译器生成警告,如下所示:
Run Code Online (Sandbox Code Playgroud)fptr = (int (*)(int))dlsym(handle, "my_function");由于此处提到的问题,未来版本可以添加新函数以返回函数指针,或者可以弃用当前接口以支持两个新函数:一个返回数据指针而另一个返回函数指针.
C++ 11解决了C/C++和POSIX之间长期不匹配的问题dlsym().reinterpret_cast只要实现支持此功能,就可以使用将函数指针转换为数据指针.
从标准来看,5.2.10段.8,"有条件地支持将函数指针转换为对象指针类型,反之亦然".1.3.5将"有条件支持"定义为"不需要支持实现的程序构造".
undefined并不一定意味着不允许,它可能意味着编译器实现者可以更自由地按照自己的意愿去做.
例如,在某些体系结构上可能无法实现 - undefined允许它们仍然具有符合标准的"C"库,即使您不能这样做.
另一个解决方案:
假设POSIX保证函数和数据指针具有相同的大小和表示形式(我找不到用于此的文本,但是引用的示例OP建议它们至少旨在满足此要求),以下方法应该起作用:
double (*cosine)(double);
void *tmp;
handle = dlopen("libm.so", RTLD_LAZY);
tmp = dlsym(handle, "cos");
memcpy(&cosine, &tmp, sizeof cosine);
Run Code Online (Sandbox Code Playgroud)
这样可以避免通过遍历char []表示形式而违反别名规则,该表示形式允许别名所有类型。
另一种方法:
union {
double (*fptr)(double);
void *dptr;
} u;
u.dptr = dlsym(handle, "cos");
cosine = u.fptr;
Run Code Online (Sandbox Code Playgroud)
但是memcpy如果您绝对希望100%正确的C语言,我会推荐这种方法。
它们可以是具有不同空间要求的不同类型.分配给一个可以不可逆地切片指针的值,以便分配返回导致不同的东西.
我相信它们可以是不同的类型,因为标准不希望限制在不需要时节省空间的可能实现,或者当大小可能导致CPU必须使用额外的垃圾来使用它等时...
| 归档时间: |
|
| 查看次数: |
12441 次 |
| 最近记录: |