利用c语言结构体和union实现类似c++的public,private的实现
最近在看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的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 找两部电影,时间有些久了,印象模糊了。第
- 下一篇: I2C和SPI总线优缺点对比