void*是C语言及其衍生语言的一个有用特性。例如,可以使用void*在C++类中存储目标C对象指针。我最近在做一个类型转换框架,由于时间限制,我有点懒-所以我使用了void*......这就是这个问题出现的原因:为什么我可以将int类型转换为void*,而不能将float类型转换为void*?
void*
vlurs2pr1#
BOOL不是C++类型,它可能是typedef或在某个地方定义的,在这些情况下,它将与int相同。例如,Windows在Windef.h中有以下内容:
typedef int BOOL;
因此,您的问题简化为:为什么可以将int类型转换为void*,而不能将float类型转换为void*?int到void* 是可以的,但通常不推荐(有些编译器会警告),因为它们在表示上本质上是相同的。指针基本上是一个整数,指向内存中的地址。float到void* 是不正确的,因为对float值的解释与表示它的实际位不同。例如,如果执行以下操作:
float x = 1.0;
它的作用是将32位内存设置为00 00 80 3f(IEEE单精度浮点值1.0的实际表示)。2当你将一个浮点数强制转换为void* 时,解释是不明确的。3你指的是指向内存中位置1的指针吗?4还是指向内存中位置3f800000(假定为小字节序)的指针?当然,如果你确定了你想要这两种情况中的哪一种,总有办法绕过这个问题。例如:
void* u = (void*)((int)x); // first case void* u = (void*)(((unsigned short*)(&x))[0] | (((unsigned int)((unsigned short*)(&x))[1]) << 16)); // second case
ssm49v7z2#
指针通常由机器内部表示为整数。C允许你在指针类型和整数类型之间来回转换。(指针值可以转换为一个足够大的整数来容纳它,也可以转换回来。)使用void*来保存非常规的整数值。语言不能保证它能工作,但是如果你想马虎一下,把自己限制在Intel和其他常见的平台上,它基本上可以勉强应付。实际上,你所做的是使用void*作为一个通用容器,不管机器使用多少字节作为指针,这在32位和64位机器之间是不同的,所以在32位平台上将long long转换为void*会丢失一些位。对于浮点数,(void*) 10.5f的意图是不明确的。您想将10.5舍入为整数,然后将其转换为无意义指针吗?不,您想将FPU使用的位模式放入无意义指针中。这可以通过赋值float f = 10.5f; void *vp = * (uint32_t*) &f;来实现,但要注意这只是无意义的:指针不是位的通用存储器。顺便说一下,最好的通用位存储是char数组,语言标准保证内存可以通过char*操作,但是您必须注意数据对齐要求。
long long
(void*) 10.5f
float f = 10.5f; void *vp = * (uint32_t*) &f;
char
char*
y1aodyip3#
Standard表示 *752整数可以转换为任何指针类型 *。没有表示任何关于指针-浮点转换的内容。
nzk0hqpo4#
考虑到您希望将float值转换为void *,有一个使用类型双关语的变通方案。这里有一个例子。
float
void *
struct mfloat { union { float fvalue; int ivalue; }; }; void print_float(void *data) { struct mfloat mf; mf.ivalue = (int)data; printf("%.2f\n", mf.fvalue); } struct mfloat mf; mf.fvalue = 1.99f; print_float((void *)(mf.ivalue));
我们使用union将浮点值(fvalue)转换为void* 的整数(ivalue),反之亦然
4条答案
按热度按时间vlurs2pr1#
BOOL不是C++类型,它可能是typedef或在某个地方定义的,在这些情况下,它将与int相同。例如,Windows在Windef.h中有以下内容:
因此,您的问题简化为:为什么可以将int类型转换为void*,而不能将float类型转换为void*?
int到void* 是可以的,但通常不推荐(有些编译器会警告),因为它们在表示上本质上是相同的。指针基本上是一个整数,指向内存中的地址。
float到void* 是不正确的,因为对float值的解释与表示它的实际位不同。例如,如果执行以下操作:
它的作用是将32位内存设置为00 00 80 3f(IEEE单精度浮点值1.0的实际表示)。2当你将一个浮点数强制转换为void* 时,解释是不明确的。3你指的是指向内存中位置1的指针吗?4还是指向内存中位置3f800000(假定为小字节序)的指针?
当然,如果你确定了你想要这两种情况中的哪一种,总有办法绕过这个问题。例如:
ssm49v7z2#
指针通常由机器内部表示为整数。C允许你在指针类型和整数类型之间来回转换。(指针值可以转换为一个足够大的整数来容纳它,也可以转换回来。)
使用
void*
来保存非常规的整数值。语言不能保证它能工作,但是如果你想马虎一下,把自己限制在Intel和其他常见的平台上,它基本上可以勉强应付。实际上,你所做的是使用
void*
作为一个通用容器,不管机器使用多少字节作为指针,这在32位和64位机器之间是不同的,所以在32位平台上将long long
转换为void*
会丢失一些位。对于浮点数,
(void*) 10.5f
的意图是不明确的。您想将10.5舍入为整数,然后将其转换为无意义指针吗?不,您想将FPU使用的位模式放入无意义指针中。这可以通过赋值float f = 10.5f; void *vp = * (uint32_t*) &f;
来实现,但要注意这只是无意义的:指针不是位的通用存储器。顺便说一下,最好的通用位存储是
char
数组,语言标准保证内存可以通过char*
操作,但是您必须注意数据对齐要求。y1aodyip3#
Standard表示 *752整数可以转换为任何指针类型 *。没有表示任何关于指针-浮点转换的内容。
nzk0hqpo4#
考虑到您希望将
float
值转换为void *
,有一个使用类型双关语的变通方案。这里有一个例子。
我们使用union将浮点值(fvalue)转换为void* 的整数(ivalue),反之亦然