搜索
bottom↓
回复: 26

对于全局的结构体变量怎么用接口函数封装?

[复制链接]

出0入0汤圆

发表于 2014-12-17 20:46:03 | 显示全部楼层 |阅读模式
前两天看了到了个关于如何避免使用全局变量的帖子:
http://www.amobbs.com/thread-5598120-1-1.html

收益颇多,用get_xxx和set_xxx接口函数把全局变量封装后感觉程序清爽多了

但是如果这个全局变量是结构体变量感觉有点问题,如果是只对这个结构体变量中一个成员进行读写操作好像不太方便啊,需要先对整个结构体变量操作,然后再操作里面的成员

对全局结构体变量进行封装有什么更好的方法么?

阿莫论坛20周年了!感谢大家的支持与爱护!!

如果想吃一顿饺子,就得从冰箱里取出肉,剁馅儿,倒面粉、揉面、醒面,擀成皮儿,下锅……
一整个繁琐流程,就是为了出锅时那一嘴滚烫流油的热饺子。

如果这个过程,禁不住饿,零食下肚了,饺子出锅时也就不香了……《非诚勿扰3》

出0入0汤圆

发表于 2014-12-17 21:41:58 | 显示全部楼层
对get_xxx和set_xxx接口函数的参数列表做些改动,增加一些标志来识别所需的成员变量。

出0入0汤圆

 楼主| 发表于 2014-12-17 22:22:54 | 显示全部楼层
dxgdsx 发表于 2014-12-17 21:41
对get_xxx和set_xxx接口函数的参数列表做些改动,增加一些标志来识别所需的成员变量。 ...

我也这么想过,但这不是得增加几条判断语句么?有没有更高效的访问方法?

出0入0汤圆

发表于 2014-12-17 22:43:31 来自手机 | 显示全部楼层
有个参数叫 void *

出0入0汤圆

发表于 2014-12-17 22:51:52 来自手机 | 显示全部楼层
不好意思,应该是说,修改结构体中的某个成员,最好还是指针访问比较简单。此时采用获取结构体指针的方式方便些。

出0入0汤圆

发表于 2014-12-17 22:54:22 | 显示全部楼层
参数什么的,最喜欢用全局变量了……

出0入0汤圆

发表于 2014-12-18 09:38:39 | 显示全部楼层
kanprin 发表于 2014-12-17 22:51
不好意思,应该是说,修改结构体中的某个成员,最好还是指针访问比较简单。此时采用获取结构体指针的方式方 ...

用指针应该是最方便的,但是同时也带来了“全局变量”类似的后果的。不太可控,需要编的人格外小心。我是这么理解的。

出0入0汤圆

发表于 2014-12-18 09:47:37 | 显示全部楼层
本帖最后由 dxgdsx 于 2014-12-18 09:56 编辑
psl_87 发表于 2014-12-17 22:22
我也这么想过,但这不是得增加几条判断语句么?有没有更高效的访问方法? ...


我觉得主要取决于是:1、以最快速度访问;2、尽可能保护全局变量,维护可读性。
如果是1,那么用指针是最快的,但是要小心使用。如果是2,那么要确保接口函数是唯一访问读写的通道,不存在其他任何方式(包括指针)。
其实可以不用判断语句就可以实现的。

出0入296汤圆

发表于 2014-12-18 10:21:13 | 显示全部楼层
请举出具体例子,我告诉你怎么弄。

出0入0汤圆

 楼主| 发表于 2014-12-18 12:39:14 | 显示全部楼层
Gorgon_Meducer 发表于 2014-12-18 10:21
请举出具体例子,我告诉你怎么弄。

谢谢傻孩子,比如我在test1.c文件里定义了一个全局结构体变量,以及相应的接口函数:

  1. static volatile GLOBAL var;

  2. GLOBAL get_var(void)
  3. {
  4.         return var;
  5. }
  6. void set_var(GLOBAL data)
  7. {
  8.         var = data;
  9. }
复制代码


然后在test1.h里定义GLOBAL结构体:
  1. typedef struct
  2. {
  3.       int a;
  4.       char b;
  5.       double c;
  6. } GLOBAL
复制代码


现在我想在test2.c文件里操作GLOBAL.b这个成员,按我的简单思路就是得先读取整个结构体变量,然后对成员b时行操作:
  1. GLOBAL  temp;

  2. temp = get_var();
  3. temp.b = 55;
  4. set_var(temp);
复制代码



按我这方法,对结构体一个成员操作就得先对整个结构体变量进行操作,感觉效率很低,不知道种情况的标准处理是怎么做的?

出0入296汤圆

发表于 2014-12-18 13:33:58 | 显示全部楼层
本帖最后由 Gorgon_Meducer 于 2014-12-18 13:35 编辑
psl_87 发表于 2014-12-18 12:39
谢谢傻孩子,比如我在test1.c文件里定义了一个全局结构体变量,以及相应的接口函数:


这种方式是不可以的,直接破坏了封装。
按道理来说,这个结构体的内容对外界应该是保密的,或者说应该是保护的。需要用掩码结构体来进行保护。
简单说,针对你举的这个例子,你不可以直接把这个结构体返回出去。
你应该直接针对结构体里面的成员建立set和get方法。这个叫做property,一个从C#借来的概念。

如果你的这个结构体是类,用户可以建立多个类的实例,则玩法是另外的样子。

出0入8汤圆

发表于 2014-12-18 13:45:53 | 显示全部楼层
psl_87 发表于 2014-12-18 12:39
谢谢傻孩子,比如我在test1.c文件里定义了一个全局结构体变量,以及相应的接口函数:


你这样等于没有封装了,又暴露了结构体的属性及方法,又名成员变量和成员函数。
只不过如今,更喜欢称为属性和方法。

最好的封装是隐藏全部的属性,不暴露出来。
对外只提供对象的构造和析构接口,以及公有接口,例如set/get接口

属性通过set/get接口来访问
比如增加一个set接口,来设置这里的b属性。

出0入0汤圆

发表于 2014-12-18 13:59:00 | 显示全部楼层
security 发表于 2014-12-18 13:45
你这样等于没有封装了,又暴露了结构体的属性及方法,又名成员变量和成员函数。
只不过如今,更喜欢称为 ...

你这么一说不就变成C++里面的理论了

出0入8汤圆

发表于 2014-12-18 14:02:02 | 显示全部楼层
本帖最后由 security 于 2014-12-18 14:05 编辑
234918154 发表于 2014-12-18 13:59
你这么一说不就变成C++里面的理论了


是的,我说的是OOP的思想
但实际项目中,可以不走这条路,但set/get接口,不对,严格应称为set/get方法
是通用的

只是这里不需要返回整个结构体
只需做小粒度的处理,即针对b属性,做相应的set/get方法。

出0入0汤圆

 楼主| 发表于 2014-12-18 14:46:25 | 显示全部楼层
谢谢楼上几位大神的解释,大概明白问题在哪,也就是说对于结构体变量,最好对里面的成员做set/get方法

但这样成员变量多的时候,每个都去做接口函数,感觉也挺费劲啊

出0入0汤圆

发表于 2014-12-18 14:54:54 | 显示全部楼层
大家还记得win系统编程时候的HANDLE吗,其实他也是个指针,称之为句柄,是因为它所指向的结构体是不开放的,而且系统升级后可能结构体也变化,这样写应用程序的人不会为了适应N个系统写N套代码了

出0入8汤圆

发表于 2014-12-18 15:24:09 | 显示全部楼层
McuPlayer 发表于 2014-12-18 14:54
大家还记得win系统编程时候的HANDLE吗,其实他也是个指针,称之为句柄,是因为它所指向的结构体是不开放的 ...

实际上Windows的HANDLE不是指针
而是类似如下机制:一个指针的索引ID值,通过这个HANDLE,在句柄表中,找到结构体的实际指针,再去访问结构体。

出0入8汤圆

发表于 2014-12-18 15:27:55 | 显示全部楼层
psl_87 发表于 2014-12-18 14:46
谢谢楼上几位大神的解释,大概明白问题在哪,也就是说对于结构体变量,最好对里面的成员做set/get方法

但 ...

那也许你就要考虑一个哲学问题:
设计上是不是需要暴露这么多属性
真的有必要让这么多属性,在外面都可以操作吗

出0入0汤圆

发表于 2014-12-18 15:28:19 | 显示全部楼层
前不久也发帖咨询ucos里面怎么减少全局变量使用,现在基本都是把变量封装成结构体,但是完全不用全局变量还是做不到。但结构体作为隐性封装外部看不到,只看到对象的构造和析构接口移植维护找变量感觉好麻烦。。。

出0入8汤圆

发表于 2014-12-18 15:34:09 | 显示全部楼层
tian_zi 发表于 2014-12-18 15:28
前不久也发帖咨询ucos里面怎么减少全局变量使用,现在基本都是把变量封装成结构体,但是完全不用全局变量还 ...

可以有Public属性的,贴上这标签,标志这属于公开的秘密。
减少全局变量,我想更多的是指:
减少全局变量的静态定义,这样在程序的生命周期内,一直占着茅坑,即便,不拉翔的话。
换句话说,全局变量,应尽可能多的生在堆上,用到时new,用完,销毁回收delete。

出0入0汤圆

发表于 2014-12-18 15:51:57 | 显示全部楼层
security 发表于 2014-12-18 15:34
可以有Public属性的,贴上这标签,标志这属于公开的秘密。
减少全局变量,我想更多的是指:
减少全局变量 ...

都是C++编程思想

出0入0汤圆

发表于 2014-12-19 09:36:24 | 显示全部楼层
我现在的做法是,使用 static  去定义结构体,对用户开放使用结构体封装的set/get接口,使用函数指针实现,set/get的返回类型为bool,方便用户检查访问成功(true)或是失败(false)

使用的时候是这样的:

uint16_t a;
inf_name *pName = (inf_name *)inf_name_new();

if ( pName->get.A( &a ) )
{
    //!< ...........
}

出100入101汤圆

发表于 2014-12-19 09:39:39 | 显示全部楼层
这个一般是定义好接口函数,传递指针给调用的。

出0入0汤圆

发表于 2014-12-19 09:39:50 | 显示全部楼层
把一个模块或功能的数据和函数(行为)整合到一起,对工作会方便很多

出0入296汤圆

发表于 2014-12-19 10:36:29 | 显示全部楼层
psl_87 发表于 2014-12-18 14:46
谢谢楼上几位大神的解释,大概明白问题在哪,也就是说对于结构体变量,最好对里面的成员做set/get方法

但 ...

你最后问的问题其实导出了一个模块封装原则:最小公开原则——简单说就是默认全部都不公开,当别人确实需要
用某个东西的时候,经过多方论证,确确实实必须开放某些部分,则应该“勉为其难”的开放满足他功能的最小信息。

出0入0汤圆

发表于 2014-12-19 10:37:13 | 显示全部楼层
看具体项目大小和资源多少吧,都封装起来,安全了,但代码多得一大堆,而且也不见得会清爽,因为每个成员都要读写,你一个几十K的资源搞这也搞不了,再这样搞就直接上C++了,那个oopc宏,折腾来折腾去只有开堆才好用,同样耗空间,最后还是放弃。。。不过里面的typedef用得蛮巧妙的

出0入0汤圆

发表于 2014-12-19 14:45:00 来自手机 | 显示全部楼层
感觉接触过c++和java后,现在看这个set/get方法就好理解多了。通过这两个接口对类(结构体)中的数据进行操作,将其中的数据保护起来,外部无权对其操作。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 00:46

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表