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

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

    关注

    5068

    文章

    19008

    浏览量

    302989
  • 结构体
    +关注

    关注

    1

    文章

    129

    浏览量

    10832

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

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

收藏 人收藏

    评论

    相关推荐

    C语言和C++中结构的区别

    同样是结构,看看在C语言和C++中有什么区别?
    的头像 发表于 10-30 15:11 132次阅读

    ota升级的库中,结构upgrade_server_info中pespconn的作用是什么?

    check_cb; struct espconn *pespconn; }; 这个结构中已经有ip,port,pespconn这个结构
    发表于 07-12 06:33

    请问esp-idf&vscode结构索引不到对应的成员如何解决?

    兄弟们,我用VSCode 初始化结构时,索引不到对应的成员,并且索引会出现不属于结构体内的东西,有解决办法吗,球球了
    发表于 06-14 06:42

    esp32调试MQTT的程序,如何对.host初始化?

    esp_mqtt_client_config_t mqtt_cfg这个结构的时候,你们例程里面只初始化url,但是我在网上看到很多地方的参考程序都是初始化这些结构
    发表于 06-11 07:55

    你是否真的了解结构占用了多少字节?

    结构成员所占内存空间大小一般情况下,如果想知道结构成员的内存占用情况需要:1、先用
    的头像 发表于 06-04 08:04 373次阅读
    你是否真的了解<b class='flag-5'>结构</b><b class='flag-5'>体</b>占用了多少字节?

    嵌入式中C语言结构基本实现

    :     在struct 中声明了一个含有若干新成员的数据类型。     tag  是结构标签。     member-list  是标准的变量定义,比如 int i; 或者 float f,或者其他
    的头像 发表于 05-11 08:49 932次阅读
    嵌入式中C语言<b class='flag-5'>结构</b><b class='flag-5'>体</b>基本实现

    定义了一个结构,但是分配的地址不连续,为什么?

    定义了一个结构,但是分配的地址不连续,是KEIL的问题还是我的问题?
    发表于 04-26 08:12

    Go语言中的函数、方法与接口详解

    Go 没有类,不过可以为结构类型定义方法方法就是一类带特殊的接收者参数的函数。方法接收者在它自己的参数列表内,位于 func 关键字和
    的头像 发表于 04-23 16:21 743次阅读

    C语言结构史上最详细的讲解【软件干货】

    struct结构数据类型 前言 我们知道,在C语言中有一些基本的数据类型,如 char int float long double string(c99) 等等数据类型,他们可以表示一些事物
    的头像 发表于 03-28 17:52 689次阅读

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

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

    经典 C 语言编程,结构和联合体如何共用?

    结构 结构占用的内存大小,首先和编译器的系统位数有关系,类似于CPU是 64 bits 还是 32 bits 的情形;其次,结构
    的头像 发表于 01-11 18:24 1254次阅读
    经典 C 语言编程,<b class='flag-5'>结构</b><b class='flag-5'>体</b>和联合体如何共用?

    结构与指针的关系

    在C语言中,结构(Struct)是一种用户自定义的数据类型,它允许您将不同类型的数据项组合在一起,以便形成一个更复杂的数据结构结构可以
    的头像 发表于 01-11 08:00 934次阅读
    <b class='flag-5'>结构</b><b class='flag-5'>体</b>与指针的关系

    keil arm工程中结构1字节对齐如何实现

    在Keil Arm工程中,结构的对齐方式可以通过使用特定的编译器指令或者关键字来实现。结构的对齐方式会直接影响结构
    的头像 发表于 01-05 14:40 3464次阅读

    golang结构如何定义?如何使用呢?

    结构是go语言最重要的数据结构之一,go和其它编程语言不一样,它没有类的概念,类比过来struct就相当于其它语言中的类,因此十分重要。
    的头像 发表于 11-28 10:36 413次阅读

    golang结构实例代码

    结构是go语言最重要的数据结构之一,go和其它编程语言不一样,它没有类的概念,类比过来struct就相当于其它语言中的类,因此十分重要。
    的头像 发表于 11-28 10:35 421次阅读