最近在看strongswan源代码,看到strongswan的代码框架很有意思,用C语言实现类的思想。当我们编写完一个模块,我们需要提供的是H的文件给其他模块使用,我们希望H文件中就只能包含一些公有函数,和一些类型的申明,不希望其他模块篡改我们C文件私有的变量,访问我们的私有方法,strongswan的代码实现这种类思想,举个简单的例子,如图:

比如左侧C文件是一个主程序,可以调用模块1和模块2提供的公有函数,这些函数在相应模块H文件中,但是也仅仅只能调用这些公有函数,模块的C文件中的私有函数和私有变量无法访问。(当然如果模块2想调用模块1的函数也类似,模块2的C文件包含模块1的H文件,图没标识)

可以先看看strongswan中模块C文件中的一部分代码,主要为了显示这种框架,基本strongswan每个模块都是这种格式,包含如下:

1.包含自己模块的头文件,头文件中有模块公有的结构体定义。

2.模块C文件定义私有结构体,私有结构体包含一个公有结构体变量,以及包含自己的私有方法或者变量。

3.模块C文件定义了公有方法METHOD(当然也包括私有方法,不过先关注公有方法)。

4.模块C文件定义了如何创建公有结构体的函数并返回公有结构体的指针。

#include "crypto_factory.h"
     
    struct private_crypto_factory_t {
            crypto_factory_t public;
            /*private method or value*/
    }
     
    METHOD(crypto_factory_t, create_verify_enumerator, enumerator_t*,
            private_crypto_factory_t *this, transform_type_t type)
    {
            /*public method code*/
     
    }
     
    crypto_factory_t *crypto_factory_create() {
     
            /*create public struct*/
     
    }

H文件摘取一部分代码,主要显示这种格式,如图:

struct crypto_factory_t {
     
            /*一堆公有函数指针*/
     
    }
    crypto_factory_t *crypto_factory_create();

而其中METHOD的方法的宏定义如下:

#define METHOD(iface, name, ret, this, ...) \
            static ret name(union {iface *_public; this;} \
            __attribute__((transparent_union)), ##__VA_ARGS__); \
            static typeof(name) *_##name = (typeof(name)*)name; \
            static ret name(this, ##__VA_ARGS__)

如果看到这个宏定义会有点晕,听我一一讲来,当然我自己编写了个简单例子可以直接理解这种框架思想,可以直接跳到例子看。

从这个宏定义来说:

1.先看第一句话,static ret name(union {iface *_public; this;} __attribute__((transparent_union)), ##__VA_ARGS__);

这个的意思是向编译器提供一个函数原型,而函数的第一个参数是一个透明联合类型,这个是用来干嘛呢,正常函数定义时候需要指定参数的类型,而设置成透明联合类型,可以让函数接受不同类型参数。

举个例子:已经定义了void func_a(int a)函数,功能是打印a的值,如果你想这个功能也接受类型float b,而你又不想重新定义另个函数,这时候可以使用透明联合类型,函数变成:void func_a(union { int a;float b;}__attribute__((transparent_union)))。

再看看第二个参数,是##__VA_ARGS__,这个是一个宏,可以接受可变数目的参数,代表就是METHOD最后面的省略号(可变参数),而加上##表示如果没有可变参数时候,去掉前面的逗号,如它允许这样调用,name(this, a, b, c),也允许只调用name(this)这样。

2.再看第二句话,先定义了一个函数指针,*_name,它的类型跟第一句话我们定义的一样,并且把我们第一句话函数定义的指针变量赋给它。可以简单理解为,第一句话我们定义了一个int *a,然后我们又定义了一个int *_a,并且把a的值赋给_a,_a=a。

3.最后一句话就很普通了,就是定义一个函数了。

第一看在想为什么要搞得这么复杂?后来慢慢理解了它的思想,这边可以先看看一个简单的例子,用这种框架思想写了一个简单的模块,我把METHOD相应的宏展开了,方便理解。

C文件,print_module.c

#include <stdio.h>
    #include <stdlib.h>
    #include "print_module.h"
     
    typedef struct private private;
    struct private {
        public p;
        int private_v1;
    };
     
    typedef union u_t
    {
        public *p1;
        private *p2;
    } u_t __attribute__((__transparent_union__));
     
    static void print_value(u_t u);
    static typeof(print_value) *_print_value = (typeof(print_value)*)print_value;
    static void print_value(private *p)
    {
        printf("%d\n",p->private_v1);
        
    }
     
    static void destory(u_t u);
    static typeof(destory) *_destory = (typeof(destory)*)destory;
    static void destory(private *p)
    {
        free(p);
    }
     
    public* create_public(void)
    {
        private *user;
        user = malloc(sizeof(*(user)));
        user->p.print = _print_value;
        user->p.destory = _destory;
        user->private_v1 = 5;
        return &user->p;
    }

H文件,print_module.h

typedef struct public public;
    struct public {
        void (*print) (public *this);
        void (*destory) (public *this);
    };
    /**
     * create a public instance.
     * */
    public* create_public(void);

main.c文件

#include <stdio.h>
    #include <stdlib.h>
    #include "print_module.h"
     
     
    int main(void)
    {
        public *user;
        user = create_public();
        user->print(user);
        user->destory(user);
     
    }

进行简单的编译并且执行

gcc -c print_module.c
    gcc main.c print_module.o -o main
    ./main
    5

从main函数开始讲起,这种框架的思想是想要调用模块,有如下几个步骤:

1.包含模块头文件;

2.调用create相关函数创建相应的模块的结构体;

3.利用这个结构体作为桥梁,访问公有的方法。

可能看到这里,这种思想已经理解了,每个C文件都会创建自己的私有结构体,C文件每个函数的输入参数都有一个私有结构体指针,这样函数就可以调用私有结构体的方法和变量,同时以一种巧妙形式把这个函数原型变形成输入参数既能用公有结构体也能用私有结构体,最终把函数指针赋值给公有结构体的成员,让公有结构体可以调用。

最后稍微讲讲public* create_public(void)这个函数作用,它通过先创建一个私有结构体,最终返回私有结构体的一部分----即公有结构体(因为公有结构体在私有结构体里,私有结构体比较大)。在这期间,给公有结构体的方法赋值,如上面看到METHOD这个宏那么复杂,其实是为了这个create函数,宏的第一句给出函数原型(也理解为定义了一个函数指针),第二句话给出了一个跟第一句话名字一样的但是加了一个下划线的函数指针,这个指针最终赋给公有结构体中相应的函数指针,为了让公有结构体能访问这个函数,还有就是给私有结构体赋自己变量和方法。

按照这种的框架思想,其他模块想要调用这个模块,就必须按照上述步骤,所得到的公有结构体自然访问不到私有变量和方法。
---------------------
作者:喝醉的鱼
来源:CSDN
原文:https://blog.csdn.net/u012895183/article/details/81544227
版权声明:本文为博主原创文章,转载请附上博文链接!

利用c语言结构体和union实现类似c++的public,private的实现相关推荐

  1. 利用C语言结构体实现学生成绩录入系统

    利用C语言结构体实现学生成绩录入系统 ##功能介绍 密码功能嵌入于主函数中,初始密码为:123456(可根据需要修改) 输入1可以调用add函数对学生的基本信息以及成绩进行输入 输入2则调用print ...

  2. 利用C语言结构体解决“各个国家体育竞赛获奖排名”问题

    一.题目描述:      输入一个正整数N代表国家个数,紧接着输入国家名称,该国家获得金牌数目,获得银牌数目,获得铜牌数目.然后根据输入输出国家获奖排名,排名规则是首先按金牌排名,如果金牌相同则比较银 ...

  3. 利用c语言结构体实现通讯录

    用结构体实现一个 可以用来存储1000个人的信息的通讯录,每个人的信息包括: 姓名.性别.年龄.电话.住址 程序如下: #include<stdio.h> #include<stri ...

  4. 【零基础学C语言】知识总结八:struct 结构体与 union 共用体

    struct 结构体 struct即结构体,C程序中经常需要用相关的不同类型的数据来描述一个数据对象.例如,描述学生的综合信息时,需要使用学生的学号.姓名.性别等不同类型的数据时,像这种数据类型总是在 ...

  5. c语言结构体单元测试,C语言结构体单元练习.doc

    C语言结构体单元练习 1.有以下定义和语句: struct student { int age; int num; }; struct student stu[3]={{1001,20},{1002, ...

  6. c++ new一个结构体_C语言结构体,又一个纸老虎,纯干货讲解(附代码)

    来源:网络,排版整理:晓宇 微信公众号:芯片之家(ID:chiphome-dy)结构体的定义结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构.结构体和其他类型基础数 ...

  7. c语言结构体成员变量私有化,C语言中结构体变量私有化详解

    C语言中结构体变量私有化详解 背景介绍 操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚 ...

  8. c语言 结构体 ppt,C语言结构体ppt课件

    <C语言结构体ppt课件>由会员分享,可在线阅读,更多相关<C语言结构体ppt课件(25页珍藏版)>请在人人文库网上搜索. 1.01,02,03,9.1 结构体,9.2 共用体 ...

  9. C语言结构体(struct)最全的讲解(万字干货)

    结构体的定义 结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构. 结构体和其他类型基础数据类型一样,例如int类型,char类型只不过结构体可以做成你想要的数据类型 ...

最新文章

  1. 数据结构与算法笔记(十三)—— 树与树的算法
  2. SparkContext源码分析
  3. 关于Tomcat端口8080占用问题(解决方法)
  4. 批处理作业调度问题 ——回溯法详解
  5. 8025枚BTC在未知钱包间转移 价值约3.09亿美元
  6. Python的第三方库requests
  7. Eclipse设置字体大小
  8. 基于Java实现的禁忌搜索算法
  9. [AngularJS面面观] 20. 依赖注入 --- instance注入器以及provider注入器
  10. 如何制作微信小程序(三个步骤开发小程序)
  11. windows-快捷键
  12. 罗技c270摄像头支持linux,罗技C270摄像头的使用心得
  13. Python爬虫之bili站的正确打开方式
  14. 水清冷冷:PSCC2021安装图文教程及学习技巧(附工具)
  15. Python学习之列表--自动超市购物车
  16. 这些有意思的女产品经理...你一定要知道
  17. [易水寒]大一实训笔记 第二篇
  18. Jupyter Nptebook里面的这几个知识点你知道吗
  19. 旅行社如何快速采集旅客信息 疫情期间旅行社护照录入系统
  20. java解包_Java的自动封包和解包(Autoboxing和AutoUnboxing)

热门文章

  1. mysql数据库中nchar_MySQL数据库中CHAR与VARCHAR之争
  2. 计算机思维采用抽象和分解,凤凰机器人----什么是计算思维?凤凰机器人的编程课中是如何体现它的?...
  3. 空标签作为占位符调整距离
  4. 大意!6行代码,“报废”5片单片机!
  5. opencv中Range类的使用
  6. 树莓派 SyntaxError: invalid syntax(python错误)
  7. 【Pandas库】(3) DataFrame的创建方法及基本操作
  8. 基于道路标线的城市环境单目定位
  9. Learn OpenGL (六):坐标系统
  10. Udacity机器人软件工程师课程笔记(二十二) - 物体识别 - 色彩直方图,支持向量机SVM