Void* 算术和类型转换
Void* arithmetic and type casting
我最近尝试通过测试一些东西来理解void*
,这里是测试代码:
#include <stdio.h>
int main(int argc, char** argv)
{
float nb2 = 2.2;
void* multi_type_ptr = &nb2;
printf("\nmulti_type_ptr:\n");
printf("Elem 1: %f\n",*(float*)multi_type_ptr);
// *(multi_type_ptr + 1) = 4;
// *(int*)(multi_type_ptr + 1) = 4;
*((int*)multi_type_ptr + 1) = 4;
printf("Elem 2: %d\n",*((int*)multi_type_ptr + 1));
return 0;
}
这条指令不能工作是因为language/compiler不知道应该向multi_type_ptr
的地址添加多少字节(它不知道指向的类型的大小通过 void*
)?
*(multi_type_ptr + 1) = 4;
还有一个 void*
不能取消引用,所以它应该转换为正确的类型,对吗?
由于提到的问题,这一行仍然无法工作以上。
*(int*)(multi_type_ptr + 1) = 4;
此作业是否有效,因为 language/compiler 理解它必须将 (1 * sizeof int)
添加到地址 of multi_type_ptr
? 我使用 Visual Studio.
中包含的 cl 编译器
*((int*)multi_type_ptr + 1) = 4;
当行首的 *
访问其内容时,(multi_type_ptr + 1)
的结果看起来仍然是 (int*)
,对吗?
在此先感谢您日后的指正、解释和加强。
*(multi_type_ptr + 1) = 4;
表达式 multi_type_ptr + 1
在 C 中无效,因为 C 不允许使用 void *
.
进行指针运算
*((int*)multi_type_ptr + 1) = 4;
此语句在您的机器中编译,因为 (int*) multi_type_ptr + 1
使用 int *
进行指针运算。尽管如此,如果结果指针与操作数(或最后一个元素之后的一个)不在同一个数组对象中,则 C 中的指针添加是未定义的行为;如果结果指针在数组对象之外,则取消引用结果指针是未定义的行为,因此在你的情况 *
表达式(以及语句)调用未定义的行为。
这里有几个问题:
Does this instruction can't work because the language/compiler dont know how much bytes it should add to the adress of multi_type_ptr (it doesn't know the size of the type pointed by void*)?
*(multi_type_ptr + 1) = 4;
是的,你是对的。一些编译器(例如 GCC)允许使用 void
指针进行指针运算,并将它们视为指向大小为 1 的对象(就像 char*
),以避免从 void*
中频繁转换来回走动。
Does this assignment works bacause the language/compiler understand it have to add (1 * sizeof int) to the adress of multi_type_ptr? I use cl compiler included in Visual Studio.
*((int*)multi_type_ptr + 1) = 4;
是的,又对了。但请注意,虽然这段代码在语法上是正确的,并且可以编译,但它在技术上是未定义的行为,原因有两个:
- 您类型双关 或类型别名
nb2
变量。也就是说,您正在使用与定义的类型不同的类型(定义为 float
,用作 int
)访问它(例外情况是您使用的是 char
指针,但事实并非如此案)。
- 如果
2*sizeof(int) > sizeof(float)
(很有可能),那么您的指针算法会将您带到 nb2
范围之外,并且您可能正在破坏堆栈。
It looks like the result of (multi_type_ptr + 1) is still an (int*) when its content is accessed by the * at the begginning of the line, am i right?
没有。 Cast 运算符具有高优先级,所以这一行:
*((int*)multi_type_ptr + 1) = 4;
实际读作:
*(((int*)multi_type_ptr) + 1) = 4;
也就是像:
int *temp1 = (int*)multi_type_ptr);
int *temp2 = t1 + 1;
*temp2 = 4;
但是,再次提防 类型别名 !
我最近尝试通过测试一些东西来理解void*
,这里是测试代码:
#include <stdio.h>
int main(int argc, char** argv)
{
float nb2 = 2.2;
void* multi_type_ptr = &nb2;
printf("\nmulti_type_ptr:\n");
printf("Elem 1: %f\n",*(float*)multi_type_ptr);
// *(multi_type_ptr + 1) = 4;
// *(int*)(multi_type_ptr + 1) = 4;
*((int*)multi_type_ptr + 1) = 4;
printf("Elem 2: %d\n",*((int*)multi_type_ptr + 1));
return 0;
}
这条指令不能工作是因为language/compiler不知道应该向multi_type_ptr
的地址添加多少字节(它不知道指向的类型的大小通过 void*
)?
*(multi_type_ptr + 1) = 4;
还有一个 void*
不能取消引用,所以它应该转换为正确的类型,对吗?
由于提到的问题,这一行仍然无法工作以上。
*(int*)(multi_type_ptr + 1) = 4;
此作业是否有效,因为 language/compiler 理解它必须将 (1 * sizeof int)
添加到地址 of multi_type_ptr
? 我使用 Visual Studio.
*((int*)multi_type_ptr + 1) = 4;
当行首的 *
访问其内容时,(multi_type_ptr + 1)
的结果看起来仍然是 (int*)
,对吗?
在此先感谢您日后的指正、解释和加强。
*(multi_type_ptr + 1) = 4;
表达式 multi_type_ptr + 1
在 C 中无效,因为 C 不允许使用 void *
.
*((int*)multi_type_ptr + 1) = 4;
此语句在您的机器中编译,因为 (int*) multi_type_ptr + 1
使用 int *
进行指针运算。尽管如此,如果结果指针与操作数(或最后一个元素之后的一个)不在同一个数组对象中,则 C 中的指针添加是未定义的行为;如果结果指针在数组对象之外,则取消引用结果指针是未定义的行为,因此在你的情况 *
表达式(以及语句)调用未定义的行为。
这里有几个问题:
Does this instruction can't work because the language/compiler dont know how much bytes it should add to the adress of multi_type_ptr (it doesn't know the size of the type pointed by void*)?
*(multi_type_ptr + 1) = 4;
是的,你是对的。一些编译器(例如 GCC)允许使用 void
指针进行指针运算,并将它们视为指向大小为 1 的对象(就像 char*
),以避免从 void*
中频繁转换来回走动。
Does this assignment works bacause the language/compiler understand it have to add (1 * sizeof int) to the adress of multi_type_ptr? I use cl compiler included in Visual Studio.
*((int*)multi_type_ptr + 1) = 4;
是的,又对了。但请注意,虽然这段代码在语法上是正确的,并且可以编译,但它在技术上是未定义的行为,原因有两个:
- 您类型双关 或类型别名
nb2
变量。也就是说,您正在使用与定义的类型不同的类型(定义为float
,用作int
)访问它(例外情况是您使用的是char
指针,但事实并非如此案)。 - 如果
2*sizeof(int) > sizeof(float)
(很有可能),那么您的指针算法会将您带到nb2
范围之外,并且您可能正在破坏堆栈。
It looks like the result of (multi_type_ptr + 1) is still an (int*) when its content is accessed by the * at the begginning of the line, am i right?
没有。 Cast 运算符具有高优先级,所以这一行:
*((int*)multi_type_ptr + 1) = 4;
实际读作:
*(((int*)multi_type_ptr) + 1) = 4;
也就是像:
int *temp1 = (int*)multi_type_ptr);
int *temp2 = t1 + 1;
*temp2 = 4;
但是,再次提防 类型别名 !