我最近通过测试一些事情试图理解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;
}
此指令是否无法工作,因为语言/编译器不知道它应该向multi_type_ptr
的地址添加多少字节(它不知道{{1指向的类型的大小) }})?
void*
此外*(multi_type_ptr + 1) = 4;
无法解除引用,因此应该将其转换为正确的类型,对吧?由于上述问题,此行仍然无效。
void*
此分配是否有效,因为语言/编译器了解它必须将*(int*)(multi_type_ptr + 1) = 4;
添加到地址(1 * sizeof int)
? 我使用Visual Studio中包含的cl编译器。
of multi_type_ptr
*((int*)multi_type_ptr + 1) = 4;
的结果看起来(multi_type_ptr + 1)
的结果仍然是(int*)
,当它的内容被行开头的*
访问时,我是对的吗?
提前感谢您对未来的纠正,解释和强化。
答案 0 :(得分:3)
*(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中的指针添加是未定义的行为,并且如果结果指针位于数组对象之外,则取消引用结果指针是未定义的行为,因此,在这种情况下,*
表达式(以及语句)会调用未定义的行为。
答案 1 :(得分:2)
这里有几个问题:
这条指令不能正常工作,因为语言/编译器不知道应该向multi_type_ptr的地址添加多少字节(它不知道void *指向的类型的大小)?
*(multi_type_ptr + 1) = 4;
是的,你是对的。一些编译器(例如GCC)允许使用void
指针进行指针运算,并将它们视为指向大小为1的对象(就像char*
),以避免void*
的频繁转换四处走动。
这个赋值是否有效,因为语言/编译器知道它必须将(1 * sizeof int)添加到multi_type_ptr的地址?我使用Visual Studio中包含的cl编译器。
*((int*)multi_type_ptr + 1) = 4;
是的,再说一遍。但请注意,虽然此代码在语法上是正确的,并且它将进行编译,但它在技术上是未定义的行为,原因有两个:
nb2
变量。那就是你使用与定义的类型不同的类型(定义为float
,用作int
)来访问它(例外情况是你使用char
指针,但这不是案件)。2*sizeof(int) > sizeof(float)
(非常可能),那么你的指针算法将你带到nb2
范围之外,你可能会破坏你的堆栈。看起来(multi_type_ptr + 1)的结果仍然是(int *),当它的内容被行开头的*访问时,我是对的吗?
没有。 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;
但同样,请注意类型别名!