Void *算术和类型转换

时间:2015-12-10 20:47:41

标签: c casting void-pointers

我最近通过测试一些事情试图理解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*),当它的内容被行开头的*访问时,我是对的吗? 提前感谢您对未来的纠正,解释和强化。

2 个答案:

答案 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;

是的,再说一遍。但请注意,虽然此代码在语法上是正确的,并且它将进行编译,但它在技术上是未定义的行为,原因有两个:

  1. 您是类型双关语类型别名 nb2变量。那就是你使用与定义的类型不同的类型(定义为float,用作int)来访问它(例外情况是你使用char指针,但这不是案件)。
  2. 如果2*sizeof(int) > sizeof(float)(非常可能),那么你的指针算法将你带到nb2范围之外,你可能会破坏你的堆栈。
  3.   

    看起来(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;
    

    但同样,请注意类型别名