为什么使用void指针来解除引用数据类型的变量?

Jai*_*esh 8 c types type-conversion void-pointers

使用void指针取消引用float变量:

#include <stdio.h>

int main() {
    float a = 7.5;
    void *vp = &a;
    printf("%f", *(float*)vp); /* Typecasting a void pointer to float for dereference */
    printf("\n");
}
Run Code Online (Sandbox Code Playgroud)

输出: 7.500000

使用整数指针取消引用变量:

#include <stdio.h>

int main() {
    float a = 7.5;
    int *ip = &a;
    printf("%f", *(float*)ip); /* Typecasting an int pointer to float for dereference */
    printf("\n");
}
Run Code Online (Sandbox Code Playgroud)

输出: 7.500000

在两者中,输出都是相同的.当我们能够通过类型转换普通指针来解决不同的数据类型变量时,是什么原因?

use*_*733 14

将任何数据指针转换为void*指针和返回都可以保证返回原始指针.

从C11标准草案N1570:

6.3.2.3指针

  1. 指针void可以转换为指向任何对象类型的指针.指向任何对象类型的指针可以转换为指向void的指针,然后再返回; 结果应该等于原始指针.

将数据指针转换为void*(int*在您的示例中)之外的其他数据指针可能有效.这取决于您使用的编译器和您所使用的系统.并非所有系统都可能对不同的指针类型使用相同的内部表示

  1. 指向对象类型的指针可以转换为指向不同对象类型的指针.如果对于引用的类型,结果指针未正确对齐(68),则行为未定义.否则,当再次转换回来时,结果将等于原始指针.当指向对象的指针转换为指向字符类型的指针时,结果指向对象的最低寻址字节.结果的连续增量(直到对象的大小)产生指向对象的剩余字节的指针.

这与严格的别名规则不同.

float a = 7.5;    
int *ip=&a;
int i = *ip; // Dereferenced using invalid type
Run Code Online (Sandbox Code Playgroud)

上面的代码打破了严格的别名规则,因为解除引用的类型与原始类型不同.这会导致未定义的行为,并且始终是无效的代码.

  • 示例:假设您的平台对浮动具有严格的对齐要求,但对于整数没有.因此,int指针可以表示为其在内存中的字节偏移量,但浮点指针可能在内存中表示为其*index*,因为假设的FPU更有效地以这种方式加载值.在这样的系统上,将`float*`转换为`void*`会将底层地址表示形式乘以`sizeof(float)`以获得字节偏移量,但将`int*`转换为`void*`是无操作.在`int*`和`float*`之间直接转换会冒UB(6.3.2.3)的风险; 通过`int`会产生垃圾. (2认同)

msc*_*msc 5

void指针是一个通用指针可容纳任何类型的地址,并且可以强制转换的任何类型的.

在第一种情况下,程序成功编译并运行时没有任何警告或错误,因为使用void指针从一种指针类型转换为另一种指针类型然后将其存储或转换为最终类型是安全的而不会丢失数据.

但在第二种情况下,GCC编译器生成了警告

prog.c: In function 'main':
prog.c:5:9: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
 int *ip=&a;
     ^
Run Code Online (Sandbox Code Playgroud)

clang编译器:

warning: incompatible pointer types initializing 'int *' with an expression of type 'float *' [-Wincompatible-pointer-types]
int *ip=&a;
     ^  ~~
Run Code Online (Sandbox Code Playgroud)

C11标准,6.3.2.3,第7段:

指向对象或不完整类型的指针可以转换为指向不同对象或不完整类型的指针.如果生成的指针未针对引用的类型正确对齐,则行为未定义.