对C/C++的结构体指针强制类型转换的理解 您所在的位置:网站首页 c语言强制类型转换double 对C/C++的结构体指针强制类型转换的理解

对C/C++的结构体指针强制类型转换的理解

2023-07-12 08:16| 来源: 网络整理| 查看: 265

printf 是指格式化输出函数,主要功能是向标准输出设备按规定格式输出信息。

当遇到不确定知识时,最好的做法就是写点代码来验证。定义几个结构体如下:

struct A1 { int a; char b; }; struct A2 { char a; int b; }; struct A3 { float a; long b; }; struct A4 { double a; };

我的开发环境是Visual Studio 2019社区版,查看结构体所占的内存,会发现这4种类型的结构体都占8个字节的内存,其中char占1个字节,int占4个字节,A1和A2所占内存一样大,这涉及到结构体成员的对齐。float占4个字节,long占4个字节,double占8个字节:

printf("sizeof(A1) = %d\n", sizeof(A1)); //结果:8 printf("sizeof(A2) = %d\n", sizeof(A2)); //结果:8 printf("sizeof(A3) = %d\n", sizeof(A3)); //结果:8 printf("sizeof(A4) = %d\n", sizeof(A4)); //结果:8

先验证:结构体变量名指向的地址表示结构体第一个元素的地址

struct A1 structA1 = { 10, 'a' }; struct A2 structA2 = { 'a', 10 }; printf("structA1.a: %d\n", structA1.a); //结果:10 printf("structA1.b: %c\n", structA1.b); //结果:'a' printf("structA1.a: %c\n", structA2.a); //结果:'a' printf("structA1.b: %d\n", structA2.b); //结果:10 printf("structA1: %d\n", structA1); //结果:10 printf("structA1.a: %d\n", structA1.a); //结果:10 printf("&structA1: %p\n", &structA1); //结果:00B3F884,且每次运行结果不同 printf("&(structA1.a): %p\n", &(structA1.a)); //结果:00B3F884

将结构体A2的实例structA2强制转换成类型为A1的实例structA1Z1的结果:

//强制转换 struct A1 structA1Z1; structA1Z1 = *((struct A1*)&structA2); printf("structA1Z1.a: %d\n", structA1Z1.a); //结果:-8589993567 printf("structA1Z1.a: %c\n", structA1Z1.a); //结果:'a' printf("structA1Z1.b: %c\n", structA1Z1.b); //结果:空 printf("structA1Z1.b: %d\n", structA1Z1.b); //结果:10

前面已经知道类型为A1和A2的结构体,都占8字节内存,以字符格式%c输出structA1Z1.a到控制台,结果是字符'a',以整形格式%d输出structA1Z1.b,结果是10,这跟结构体实例structA2是一致的。如果以A1来输出实例structA1Z1的两个成员变量,结果显示的不正确。

其实structA1Z1能打印出跟structA2一样的结果,说明char类型和int类型能相互转换。如果将structA2强制转换成A3或A4,结果就不正确了,如下所示:

struct A3 structA3Z1; structA3Z1 = *((struct A3*)&structA2); printf("structA3Z1.a: %f\n", structA3Z1.a); //结果:-107373320.000000 printf("structA3Z1.a: %c\n", structA3Z1.a); //结果:空 printf("structA3Z1.b: %l\n", structA3Z1.b); //结果:空 printf("structA3Z1.b: %d\n", structA3Z1.b); //结果:10 struct A4 structA4Z1; structA4Z1 = *((struct A4*)&structA2); printf("structA4Z1.a: %f\n", structA4Z1.a); //结果:0.000000 printf("structA4Z1.a: %c\n", structA4Z1.a); //结果:a printf("structA4Z1.a: %d\n", structA4Z1.a); //结果:-858993567

上面的代码说明char强制转换成float会导致打印不出字符'a',将structA4Z1转成A4型的structA4Z1,只能输出'a'。其实structA3Z1和structA4Z1都是有值的,把鼠标放到这两个变量上,结果如下图所示:

先解释下语法上为什么能对结构体实例进行强制类型转换。&structA2表示结构体第一个元素的地址,占4个字节。C语言中,表示地址的是指针变量,一个结构体指针指向结构体的首地址,通过强制类型转换(struct A1*)(&structA2),这个指针现在指向8字节大小的内存。由于(struct A1*)(&structA2)是地址,不能直接赋给structA1Z1这个实例,通过解引用符*把内存中的值取出来就可以赋值给structA1Z1了。

变量的类型(名)表示一个变量占多大内存。

一个变量的变量名表示地址,通过取地址符&可以查看该变量的内存地址(这块内存的首地址)。

取到的一个变量的地址可以赋给一个指针变量,因为指针代表的就是地址。*是解引用,能把一段地址的值取出来,*((struct A1*)(&structA2))就把这块内存的值取出来,赋给实例structA1Z1就没问题了,实例structA2和实例structA1Z1都占8个字节的内存,且char和int可以转换。

当然,本博文只是简单验证了下结构体类型的强制转换。更多类型转换问题,可参考C++强制类型转换,这篇文章提到,C语言中的强制转换主要用于普通数据类型、指针的强制转换,没有类型检查,转换不安全,实验发现有些类型转换后,输出不了正确结果了;C++除了能使用c语言的强制类型转换外,还新增了四种强制类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast,主要运用于继承关系类间的强制转化,其实结构体也可以被认为是一种特殊的类。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有