0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

隐藏结构体成员的方法与问题

奈因PCB电路板设计 来源:最后一个bug 作者:bug菌 2021-08-11 10:18 次阅读

今天主要跟大家分享一种隐藏结构体成员的方法,很多地方也叫“不完全类型”,所以这里bug菌以更加通俗易懂的方式跟大家介绍下,并且谈一谈相关的一些问题。

1

引出话题

首先我们来看下面一个最简单的例子:

参考代码:

1/************filename:

App.h*************/ 2#ifndef __APP_H__ 3#define __APP_H__ 4 5 6typedef struct _tag_StObj stObj; 7struct _tag_StObj 8{ 9 int member1;

10 int member2;

11};

12 13//interface

14 15int sAdd(stObj *pObj); 16 17#endif 18 19/************filename: App.c*************/ 20#include “App.h” 21 22/**********************************

23 * Function : sAdd 24 * Note :加法函数,也是接口函数 25 * Author: bug菌

26 **********************************/ 27int sAdd(stObj *pObj) 28{ 29 return (pObj-》member1 + pObj-》member2); 30} 31 32/************filename: main.c*************/ 33#include 《stdio.h》 34#include

“。/App/App.h” 35 36int main(void) 37{ 38 stObj Obj; 39 Obj.member1 = 1;

40 Obj.member2 = 2; 41 42 printf(“result = %d ”,sAdd(&Obj)); 43 44 return 0; 45}

以上是三个文件中的内容,程序编译通过,输出结果为3。在main函数中均可以通过结构体定义变量,并且直接访问其结构体内部的成员,而很多人觉得结构体作为一个对象不应该把其内部数据全部暴露出来供开放访问,非常不利于内部实现细节的封装和对象数据的安全性。那有什么办法不允许外部访问结构体成员呢?

2

不完全类型

“不完全类型”看起来很深奥的名字,主要还是翻译问题吧,从字面上来说就是不那么完整的类型,我们知道像常规的char,int,float类型,要作为一个类型,那么平台肯定为他们提供了所占据的内存大小和处理方式,而不完全类型几乎没有在定义的时候给出,比如没有指定长度的数组array[],他也是一种不完全类型,虽然表示的是数组,可是你不知道它到底有多大,这样编译器就不能够为其分配内存而定义报错。下面修改下之前的程序,把结构体定义放到对应的app.c文件,而app.h中留下一个啥也不含的同名结构体“空壳”。

1/************filename: App.h*************/ 2#ifndef __APP_H__ 3#define __APP_H__ 4 5 6typedef struct _tag_StObj stObj;

7/*struct _tag_StObj 8{ 9 int member1;

10 int member2; 11};*/ 12 13//interface 14 15int sAdd(stObj *pObj);

16 17#endif 18 19/************filename: App.c*************/ 20#include “App.h” 21 22struct _tag_StObj 23{ 24 int member1; 25 int member2; 26};

27/********************************** 28 * Function : sAdd 29 * Note :加法函数,也是接口函数 30 * Author:

bug菌 31 **********************************/ 32int sAdd(stObj *pObj) 33{ 34 return (pObj-》member1 + pObj-》member2);

35} 36 37/************filename: main.c*************/ 38#include 《stdio.h》 39#include “。/App/App.h” 40 41int main(void) 42{ 43 stObj Obj;

44 Obj.member1 = 1; 45 Obj.member2 = 2;

46 47 printf(“result = %d ”,sAdd(&Obj)); 48 49 return 0; 50}

编译结果:

此时编译器会报一个error,表示不知道该结构体到底是多大,如果你要是问App.c文件里面不是定义了结构体成员吗?怎么还会报错?你需要看一下bug菌的往期精彩,C程序的编译都是以源文件为单元展开的。

3

求助指针

把前面的main.c改改看能不能编译通过:

1/************filename: main.c*************/ 2 3#include 《stdio.h》 4#include “。/App/App.h” 5 6int main(void) 7{ 8 stObj *Obj; 9 //Obj.member1 = 1;

10 //Obj.member2 = 2; 11 12 printf(“result = %d ”,sAdd(Obj)); 13 14 return 0; 15}

然而此时编译通过:

当然上面程序语法没问题,运行却是有问题的,定义了一个野指针,一旦运行基本上都会奔溃。并且不能通过指针直接访问结构体成员,因为这是一个不知道成员的结构体“空壳”,同样sizeof也检测不了大小。

那问题来了,为什么用结构体定义变量不行,而定义成指针却可以呢?其实这个问题与bug菌之前谈到的可以定义成void*指针变量,却不能定义为void变量是相同的道理,因为指针的大小一般平台和编译器确定下来就基本确定下来了,它不依赖于所指向的对象类型,同样void也是一个不完全类型。

4

隐藏结构体成员

现在遵循两个原则:1、不能直接用不完全类型定义变量,可以定义指针:2、不能够访问其结构体内部成员,因为根本不知道。

参考代码:

1/************filename: App.h*************/ 2#ifndef __APP_H__ 3#define __APP_H__ 4 5 6typedef struct _tag_StObj stObj;

7 8//interface 9stObj * sCreate(int member1,int member2); 10int sAdd(stObj *pObj);

11 12 13#endif 14 15/************filename: App.c*************/ 16#include “App.h” 17 18struct _tag_StObj 19{ 20 int member1; 21 int member2; 22}; 23 24/********************************** 25 * Function : sCreate 26 * Note :创建函数,也是接口函数 27 * Author: bug菌 28 **********************************/ 29stObj * sCreate(int member1,int member2) 30{ 31 static stObj staticObj;

32 33 staticObj.member1 = member1; 34 staticObj.member2 = member2; 35 36 return &staticObj; 37} 38 39 40/********************************** 41 * Function : sAdd 42 * Note :加法函数,也是接口函数 43 * Author: bug菌 44 **********************************/ 45int sAdd(stObj *pObj) 46{ 47 return (pObj-》member1 + pObj-》member2);

48} 49 50/************filename: main.c*************/ 51 52#include 《stdio.h》 53#include “。/App/App.h” 54 55int main(void) 56{ 57 stObj *Obj; 58 59 Obj = sCreate(3,5); //内部构造结构体

60 61 printf(“result = %d ”,sAdd(Obj)); //调用相应的接口 62 63 return 0; 64}

编译成功,运行OK,结果如下:

那么不完全类型隐藏结构体成员的目的基本上就达到了,以后外部也是无法通过结构体变量直接访问成员了,只能对象自身在相应的.c文件中定义对应的接口,然后声明在对应的interface中供外部使用。

5

but

那么我们回过头来想想这样的不完全类型究竟做了啥?1)不允许外部访问数据细节,因为这个类型不完整,编译器把握不住~2)全程通过指针传递,本质上和void*差别不大,但是他可以进行类型的检查,这样代码的数据意义更加的明确。

当我们使用不完全结构体类型,结构体所有的成员都变成了私有,即这一种封装私有数据的方式,且均需要通过相应的接口函数访问,确实一种好的面向对象的封装方式。但是完全私有的封装还是比较麻烦,还是要做到“公私分明”,函数调用也需要一定的开销,就看工程师们怎么去平衡“性价比”了。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    4981

    文章

    18273

    浏览量

    288338
  • 结构体
    +关注

    关注

    1

    文章

    125

    浏览量

    10749

原文标题:如何隐藏"结构体对象"成员?

文章出处:【微信号:pcbgood,微信公众号:奈因PCB电路板设计】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    求助,请问一个结构如何全部定义到 __attribute__ 区域?

    请问一个结构如何全部定义到 __attribute__ 区域? 例如我这里涉及到一些高速计算的缓存,计划将缓存数据存储到 __attribute__ 区域。 三个结构 ,每个
    发表于 01-16 07:29

    为什么我定义的结构不能用-->来调用结构的元素?

    结构代码部分 typedef unsigned int uint_32t; typedef unsigned short uint_16t; typedef struct { uint_32t
    发表于 11-11 19:06

    求助,结构变量定义引用问题求解

    |= mask; } 如以上语句,GPIO_Type是个结构定义,定义了一个*base变量,在引用其中的成员时,是base->IMR的方式。这怎么理解; 如果是
    发表于 10-27 06:06

    FAQ0066结构成员未完全初始化导致程序异常的解决方法

    使用非官方程序,由于某些外设驱动在配置结构时,未完全初始化所有成员,导致程序运行异常。以 FSMC 为例,FSMC_NORSRAMInitStructure 结构
    发表于 10-20 06:59

    如何在DEBUG的时候实时观察SYSTICK结构的数据?

    在DEBUG这个delay函数的时候,想要观察SysTick指向的结构数据变化,但是添加了SysTick到Watch1中,观察不了。 目前是定义了一个u32 temp采用了将SysTick中
    发表于 10-18 06:29

    为什么ST库函数结构没加对齐地址是连续的?

    为什么ST库函数结构没加对齐,地址是连续的
    发表于 10-15 08:11

    结构在FLASH的存放中,数据地址是连续的吗?

    结构在FLASH的存放中,数据地址是连续的吗
    发表于 10-12 06:06

    结构struct和联合体union的区别?

    结构struct和联合体union的区别?
    发表于 10-11 08:21

    结构为什么有的时候用点,有的时候用箭头?

    结构为什么有的时候用点,有的时候用箭头
    发表于 10-10 07:18

    C语言中的结构指针在访问的时候怎么读取成员变量的数据?

    C语言中的结构指针在访问的时候怎么读取成员变量的数据
    发表于 10-10 07:07

    keil MDK中程序读写结构成员进入HARDFAUL HANDLE RET为什么无法读写?

    。可是问题出现了,我在程序之中对结构成员eedata.kt0[]进行读写时,keil就会立刻跳入到起始文件的HARDFAUL HANDLE RET处,然后怎么运行都停在那,如果我将对结构
    发表于 08-25 07:58

    结构成员变量的引用方法123

    这里采用的是常用的typedef关键字进行定义结构体类型,可以看到student_t这种数据类型里面有4个成员变量,分别是学号、姓名、分数、年龄,这些成员变量既然是变量就应该满足变量的基本特征,也就是说可以被赋值,可以被引用,下
    的头像 发表于 07-08 14:45 1676次阅读
    <b class='flag-5'>结构</b>体<b class='flag-5'>成员</b>变量的引用<b class='flag-5'>方法</b>123

    IAR开发M453时出现定义结构错误的原因?

    在使用IAR开发M453时出现了一个问题,定义一个空结构就会报错,但是在结构中添加成员编译正常; 首先我想是不是对
    发表于 06-25 07:35

    结构成员变量的引用方法

    这里默认大家是了解结构体这种数据类型的,如果不了解可以参考往期相关文章,好了下面开始这次的内容分享
    发表于 06-23 17:52 3063次阅读
    <b class='flag-5'>结构</b>体<b class='flag-5'>成员</b>变量的引用<b class='flag-5'>方法</b>

    欧姆龙NX结构体应用方法

    欧姆龙NX结构体应用方法
    的头像 发表于 06-15 10:23 814次阅读
    欧姆龙NX<b class='flag-5'>结构</b>体应用<b class='flag-5'>方法</b>