加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

嵌入式 C 保護(hù)結(jié)構(gòu)體的方式

07/25 11:20
1720
閱讀需 13 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

之前分享的文章:嵌入式 C 語言知識點(diǎn),掩碼結(jié)構(gòu)體,似乎有些爭議?

不知道是因?yàn)楹甑膶?shí)現(xiàn)看不懂還是用法不懂?掩碼結(jié)構(gòu)體宏的實(shí)現(xiàn)本質(zhì)上就是使用一個(gè)掩碼數(shù)組 chMask 把結(jié)構(gòu)體保護(hù)起來。

用法可以結(jié)合大佬的PLOOC使用示例及其基于C語言的面向?qū)ο缶幊?傻孩子.pdf(本公眾號聊天界面回復(fù):基于C語言的面向?qū)ο缶幊?/strong>)來一起看:

https://github.com/GorgonMeducer/PLOOC

同樣,也可以結(jié)合使用不完全類型(Incomplete Types)來保護(hù)結(jié)構(gòu)體的方式一起看一下,這個(gè)之前有分享過。這里也一起分享下。

C語言中使用不完全類型(Incomplete Types)來保護(hù)結(jié)構(gòu)體的方式,主要涉及到在聲明結(jié)構(gòu)體時(shí)不提供完整的定義,僅在需要時(shí)(如在其源文件中)才給出完整的定義。這種方式的的優(yōu)點(diǎn)和缺點(diǎn):

優(yōu)點(diǎn):

封裝性增強(qiáng):使用不完全類型可以在一定程度上隱藏結(jié)構(gòu)體的內(nèi)部細(xì)節(jié),防止外部代碼直接訪問結(jié)構(gòu)體的成員,從而提高代碼的封裝性和安全性。

模塊間解耦:通過不完全類型聲明,可以在多個(gè)模塊之間傳遞結(jié)構(gòu)體的指針,而無需暴露結(jié)構(gòu)體的完整定義。這有助于減少模塊間的耦合度,使得系統(tǒng)更加靈活和易于維護(hù)。

缺點(diǎn):

使用限制:不完全類型有一些使用上的限制,比如不能直接使用sizeof運(yùn)算符來獲取不完全類型的大?。ㄒ?yàn)?a class="article-link" target="_blank" href="/baike/1572830.html">編譯器不知道其完整定義)。這可能導(dǎo)致在需要知道結(jié)構(gòu)體大小的情況下無法使用不完全類型。

容易出錯(cuò):如果在使用不完全類型時(shí)沒有正確地提供其完整定義,或者在多個(gè)地方提供了不一致的定義,都可能導(dǎo)致編譯錯(cuò)誤或運(yùn)行時(shí)錯(cuò)誤。

什么是不完全類型?

C/C++中不完全類型有三種不同形式:void、未指定長度的數(shù)組以及具有非指定內(nèi)容的結(jié)構(gòu)和聯(lián)合。使用不完全類型的指針或引用,不需要知道類型的全部內(nèi)容。比如:

我們常用以下方式聲明數(shù)組:

extern?int?array[];

此時(shí)的array就是一個(gè)不完全類型的數(shù)組,一般這樣的數(shù)組聲明會(huì)放在.h中,而其定義放在.c中,在定義的時(shí)候在給出數(shù)組的具體長度,若之后有需要改變數(shù)組的長度時(shí),直接改.c里的就可以,對外的.h就保持原樣不用修改。

用數(shù)組來說明可能還是有點(diǎn)不太好理解,下面我們用結(jié)構(gòu)體的例子來做說明。

在此之前,我們先思考一個(gè)問題,我們的結(jié)構(gòu)體實(shí)體是在頭文件中定義還是源文件中定義呢?

實(shí)際上,在頭文件、源文件中定義都可以。

下面我們以一個(gè)動(dòng)態(tài)數(shù)組的管理為例來做一些演示說明。

動(dòng)態(tài)數(shù)組,是相對于靜態(tài)數(shù)組而言。靜態(tài)數(shù)組的長度是預(yù)先定義好的,在整個(gè)程序中,一旦給定大小后就無法改變。而動(dòng)態(tài)數(shù)組則不然,它可以隨程序需要而重新指定大小。

動(dòng)態(tài)數(shù)組的內(nèi)存空間是從堆(heap)上分配(即動(dòng)態(tài)分配)的。是通過執(zhí)行代碼而為其分配存儲(chǔ)空間。當(dāng)程序執(zhí)行到這些語句時(shí),才為其分配。程序員自己負(fù)責(zé)釋放內(nèi)存。使用動(dòng)態(tài)數(shù)組的優(yōu)點(diǎn)是可以根據(jù)用戶需要,有效利用存儲(chǔ)空間。

(1)結(jié)構(gòu)體實(shí)體定義在頭文件中

比如我們本次的demo有如下三個(gè)文件:

此時(shí)dynamic_array.h的內(nèi)容如下:

我們創(chuàng)建了一些接口函數(shù)來操作DA對象,我們希望他人可以使用我們的這些接口來操作數(shù)據(jù)。并且,一般我們使用其它人寫的代碼時(shí),一般也是優(yōu)先找到相關(guān)頭文件,然后調(diào)用頭文件里提供的對外接口函數(shù)。

但是,從這個(gè)頭文件中,我們不僅僅看到了一些對外接口,還可以看到結(jié)構(gòu)體實(shí)體。于是乎,可能就有些人寫出這樣的代碼:

命名有接口可以用,卻偏偏有人喜歡直接操作數(shù)據(jù),這是比較容易出錯(cuò)的做法。而且調(diào)用者推鍋的理由很充足:你暴露數(shù)據(jù)給我,我為什么不可以直接操控你的數(shù)據(jù),我就不喜歡用你提供的接口,咋的。。。

所以dynamic_array.h的提供者還是得背鍋。

(2)結(jié)構(gòu)體實(shí)體定義在源文件中

為了不被推鍋,我們把我們的頭文件改為:

此時(shí),這里的dynamic_array_def結(jié)構(gòu)類型就是一個(gè)不完全類型。

我們把結(jié)構(gòu)體實(shí)體定義挪到源文件中,這時(shí)候調(diào)用者看不到dynamic_array_def里有什么數(shù)據(jù)了,間接得就可以強(qiáng)迫調(diào)用者使用我們提供的接口了。此時(shí)如果出問題被推鍋,那我們也樂意接鍋,樂意查找問題呀。

最后,順便貼一下本demo工程完整代碼,有需要的朋友自?。?/p>

dynamic_array.h:
/*?公眾號:嵌入式大雜燴?*/
#ifndef?__DYNAMIC_ARRAY_H
#define?__DYNAMIC_ARRAY_H

/*?結(jié)構(gòu)體“重命名”?*/
typedefstruct?dynamic_array?dynamic_array_def;

/*?初始化dynamic_array?*/
dynamic_array_def?*DA_Init(void);

/*?銷毀dynamic_array?*/
voidDA_Clean(dynamic_array_def?*pThis);

/*?設(shè)置dynamic_array長度?*/
voidDA_SetSize(dynamic_array_def?*pThis,?unsigned?len);

/*?獲取dynamic_array長度?*/
unsignedDA_GetSize(dynamic_array_def?*pThis);

/*?設(shè)置dynamic_array某元素的值?*/
intDA_SetValue(dynamic_array_def?*pThis,?unsigned?index,?int?value);

/*?獲取dynamic_array某元素的值?*/
intDA_GetValue(dynamic_array_def?*pThis,?unsigned?index,?int?*pValue);

#endif
dynamic_array.c:
/*?公眾號:嵌入式大雜燴?*/
#include?"dynamic_array.h"
#include?<stdlib.h>

/*?創(chuàng)建一個(gè)動(dòng)態(tài)數(shù)組結(jié)構(gòu)體模板?*/
struct?dynamic_array
{
int*array;
unsigned?len;
};

/*?初始化dynamic_array?*/
dynamic_array_def?*DA_Init(void)
{
????dynamic_array_def?*pArray?=malloc(sizeof(dynamic_array_def));

????pArray->array=NULL;
????pArray->len?=0;
}

/*?銷毀dynamic_array?*/
voidDA_Clean(dynamic_array_def?*pThis)
{
free(pThis->array);
????pThis->len?=0;
free(pThis);
}

/*?設(shè)置dynamic_array長度?*/
voidDA_SetSize(dynamic_array_def?*pThis,?size_t?len)
{
????pThis->len?=?len;
????pThis->array=(int*)realloc(pThis->array,?pThis->len*sizeof(int));
}

/*?獲取dynamic_array長度?*/
size_tDA_GetSize(dynamic_array_def?*pThis)
{
return?pThis->len;
}

/*?設(shè)置dynamic_array某元素的值?*/
intDA_SetValue(dynamic_array_def?*pThis,?size_t?index,?int?value)
{
if(index?>?pThis->len)
{
return-1;
}

????pThis->array[index]=?value;
return0;
}

/*?獲取dynamic_array某元素的值?*/
intDA_GetValue(dynamic_array_def?*pThis,?size_t?index,?int?*pValue)
{
if(index?>?pThis->len)
{
return-1;
}

*pValue?=?pThis->array[index];
return0;
}
main.c
/*?公眾號:嵌入式大雜燴?*/
#include?<stdio.h>
#include?<stdlib.h>
#include?"dynamic_array.h"

intmain(void)
{
int?arr_elem?=0;

/*?初始化一個(gè)動(dòng)態(tài)數(shù)組?*/
????dynamic_array_def?*pArray?=?DA_Init();

/*?設(shè)置數(shù)組長度為10?*/
????DA_SetSize(pArray,10);

/*?給數(shù)組元素賦值?*/
for(int?i?=0;?i?<10;?i++)
{
????????DA_SetValue(pArray,?i,?i);
}

/*?遍歷數(shù)組元素并打印?*/
for(int?i?=0;?i?<10;?i++)
{
????????DA_GetValue(pArray,?i,&arr_elem);
printf("%d?",?arr_elem);
}

/*?數(shù)組清理?*/
????DA_Clean(pArray);

return0;
}

編譯、運(yùn)行:

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險(xiǎn)等級 參考價(jià)格 更多信息
SN74LVC2G74DCURE4 1 Texas Instruments Single Positive-Edge-Triggered D-Type Flip-Flop with Clear and Preset 8-VSSOP -40 to 125

ECAD模型

下載ECAD模型
$0.62 查看
AFBR-57B4APZ 1 Broadcom Limited Transceiver,
$69.51 查看
KSZ9031RNXIC-TR 1 Microchip Technology Inc IC TXRX ETHERNET

ECAD模型

下載ECAD模型
$3.71 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

本公眾號專注于嵌入式技術(shù),包括但不限于C/C++、嵌入式、物聯(lián)網(wǎng)、Linux等編程學(xué)習(xí)筆記,同時(shí),公眾號內(nèi)包含大量的學(xué)習(xí)資源。歡迎關(guān)注,一同交流學(xué)習(xí),共同進(jìn)步!