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;

是的,又对了。但请注意,虽然这段代码在语法上是正确的,并且可以编译,但它在技术上是未定义的行为,原因有两个:

  1. 类型双关类型别名 nb2 变量。也就是说,您正在使用与定义的类型不同的类型(定义为 float,用作 int)访问它(例外情况是您使用的是 char 指针,但事实并非如此案)。
  2. 如果 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;

但是,再次提防 类型别名 !