0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C語(yǔ)言的驅(qū)動(dòng)法編程詳細(xì)解析

硬件攻城獅 ? 來(lái)源:博客園 ? 2023-03-08 10:46 ? 次閱讀

1. 概念提出

所謂表驅(qū)動(dòng)法(Table-Driven Approach)簡(jiǎn)而言之就是用查表的方法獲取數(shù)據(jù)。此處的“表”通常為數(shù)組,但可視為數(shù)據(jù)庫(kù)的一種體現(xiàn)。

根據(jù)字典中的部首檢字表查找讀音未知的漢字就是典型的表驅(qū)動(dòng)法,即以每個(gè)字的字形為依據(jù),計(jì)算出一個(gè)索引值,并映射到對(duì)應(yīng)的頁(yè)數(shù)。相比一頁(yè)一頁(yè)地順序翻字典查字,部首檢字法效率極高。

具體到編程方面,在數(shù)據(jù)不多時(shí)可用邏輯判斷語(yǔ)句(if…else或switch…case)來(lái)獲取值;但隨著數(shù)據(jù)的增多,邏輯語(yǔ)句會(huì)越來(lái)越長(zhǎng),此時(shí)表驅(qū)動(dòng)法的優(yōu)勢(shì)就開始顯現(xiàn)。例如,用36進(jìn)制(A表示10,B表示11,…)表示更大的數(shù)字,邏輯判斷語(yǔ)句如下:

if(ucNum

當(dāng)然也可以用switch…case結(jié)構(gòu),但實(shí)現(xiàn)都很冗長(zhǎng)。而用表驅(qū)動(dòng)法(將numChar存入數(shù)組)則非常直觀和簡(jiǎn)潔。如:

CHARaNumChars[]={'0','1','2',/*3~9*/'A','B','C',/*D~Y*/'Z'};
CHARucNumChar=aNumChars[ucNum%sizeof(aNumChars)];

像這樣直接將變量當(dāng)作下數(shù)組下標(biāo)來(lái)讀取數(shù)值的方法就是直接查表法。

注意,如果熟悉字符串操作,則上述寫法可以更簡(jiǎn)潔:

CHARucNumChar="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[ucNum];

使用表驅(qū)動(dòng)法時(shí)需要關(guān)注兩個(gè)問(wèn)題:一是如何查表,從表中讀取正確的數(shù)據(jù);二是表里存放什么,如數(shù)值或函數(shù)指針。

常用的查表方式有直接查找、索引查找和分段查找等。

1.1.1 直接查找

即直接通過(guò)數(shù)組下標(biāo)獲取到數(shù)據(jù)。如果熟悉哈希表的話,可以很容易看出這種查表方式就是哈希表的直接訪問(wèn)法。

如獲取星期名稱,邏輯判斷語(yǔ)句如下:

if(0==ucDay)
{
pszDayName="Sunday";
}
elseif(1==ucDay)
{
pszDayName="Monday";
}
//......
elseif(6==ucDay)
{
pszDayName="Saturday";
}

而實(shí)現(xiàn)同樣的功能,可將這些數(shù)據(jù)存儲(chǔ)到一個(gè)表里:

CHAR*paNumChars[]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
CHAR*pszDayName=paNumChars[ucDay];

類似哈希表特性,表驅(qū)動(dòng)法適用于無(wú)需有序遍歷數(shù)據(jù),且數(shù)據(jù)量大小可提前預(yù)測(cè)的情況。

對(duì)于過(guò)于復(fù)雜和龐大的判斷,可將數(shù)據(jù)存為文件,需要時(shí)加載文件初始化數(shù)組,從而在不修改程序的情況下調(diào)整里面的數(shù)值。

有時(shí),訪問(wèn)之前需要先進(jìn)行一次鍵值轉(zhuǎn)換。如表驅(qū)動(dòng)法表示端口忙閑時(shí),需將槽位端口號(hào)映射為全局編號(hào)。所生成的端口數(shù)目大小的數(shù)組,其下標(biāo)對(duì)應(yīng)全局端口編號(hào),元素值表示相應(yīng)端口的忙閑狀態(tài)。

1.1.2 索引查找

有時(shí)通過(guò)一次鍵值轉(zhuǎn)換,依然無(wú)法把數(shù)據(jù)(如英文單詞等)轉(zhuǎn)為鍵值。此時(shí)可將轉(zhuǎn)換的對(duì)應(yīng)關(guān)系寫到一個(gè)索引表里,即索引訪問(wèn)。

如現(xiàn)有100件商品,4位編號(hào),范圍從0000到9999。此時(shí)只需要申請(qǐng)一個(gè)長(zhǎng)度為100的數(shù)組,且對(duì)應(yīng)2位鍵值。但將4位的編號(hào)轉(zhuǎn)換為2位的鍵值,可能過(guò)于復(fù)雜或沒(méi)有規(guī)律,最合適的方法是建立一個(gè)保存該轉(zhuǎn)換關(guān)系的索引表。采用索引訪問(wèn)既節(jié)省內(nèi)存,又方便維護(hù)。比如索引A表示通過(guò)名稱訪問(wèn),索引B表示通過(guò)編號(hào)訪問(wèn)。

1.1.3 分段查找

通過(guò)確定數(shù)據(jù)所處的范圍確定分類(下標(biāo))。有的數(shù)據(jù)可分成若干區(qū)間,即具有階梯性,如分?jǐn)?shù)等級(jí)。此時(shí)可將每個(gè)區(qū)間的上限(或下限)存到一個(gè)表中,將對(duì)應(yīng)的值存到另一表中,通過(guò)第一個(gè)表確定所處的區(qū)段,再由區(qū)段下標(biāo)在第二個(gè)表里讀取相應(yīng)數(shù)值。注意要留意端點(diǎn),可用二分法查找,另外可考慮通過(guò)索引方法來(lái)代替。

如根據(jù)分?jǐn)?shù)查績(jī)效等級(jí):

#defineMAX_GRADE_LEVEL(INT8U)5
DOUBLEaRangeLimit[MAX_GRADE_LEVEL]={50.0,60.0,70.0,80.0,100.0};
CHAR*paGrades[MAX_GRADE_LEVEL]={"Fail","Pass","Credit","Distinction","HighDistinction"};

staticCHAR*EvaluateGrade(DOUBLEdScore)
{
INT8UucLevel=0;
for(;ucLevel

上述兩張表(數(shù)組)也可合并為一張表(結(jié)構(gòu)體數(shù)組),如下所示:

typedefstruct{
DOUBLEaRangeLimit;
CHAR*pszGrade;
}T_GRADE_MAP;

T_GRADE_MAPgGradeMap[MAX_GRADE_LEVEL]={
{50.0,"Fail"},
{60.0,"Pass"},
{70.0,"Credit"},
{80.0,"Distinction"},
{100.0,"HighDistinction"}
};

staticCHAR*EvaluateGrade(DOUBLEdScore)
{
INT8UucLevel=0;
for(;ucLevel

該表結(jié)構(gòu)已具備的數(shù)據(jù)庫(kù)的雛形,并可擴(kuò)展支持更為復(fù)雜的數(shù)據(jù)。其查表方式通常為索引查找,偶爾也為分段查找;當(dāng)索引具有規(guī)律性(如連續(xù)整數(shù))時(shí),退化為直接查找。

使用分段查找法時(shí)應(yīng)注意邊界,將每一分段范圍的上界值都考慮在內(nèi)。找出所有不在最高一級(jí)范圍內(nèi)的值,然后把剩下的值全部歸入最高一級(jí)中。有時(shí)需要人為地為最高一級(jí)范圍添加一個(gè)上界。

同時(shí)應(yīng)小心不要錯(cuò)誤地用“<”來(lái)代替“<=”。要保證循環(huán)在找出屬于最高一級(jí)范圍內(nèi)的值后恰當(dāng)?shù)亟Y(jié)束,同時(shí)也要保證恰當(dāng)處理范圍邊界。

1.2 實(shí)戰(zhàn)示例

本節(jié)多數(shù)示例取自實(shí)際項(xiàng)目。表形式為一維數(shù)組、二維數(shù)組和結(jié)構(gòu)體數(shù)組;表內(nèi)容有數(shù)據(jù)、字符串和函數(shù)指針。基于表驅(qū)動(dòng)的思想,表形式和表內(nèi)容可衍生出豐富的組合。

1.2.1 字符統(tǒng)計(jì)

問(wèn)題:統(tǒng)計(jì)用戶輸入的一串?dāng)?shù)字中每個(gè)數(shù)字出現(xiàn)的次數(shù)。

普通解法主體代碼如下:

INT32UaDigitCharNum[10]={0};/*輸入字符串中各數(shù)字字符出現(xiàn)的次數(shù)*/
INT32UdwStrLen=strlen(szDigits);

INT32UdwStrIdx=0;
for(;dwStrIdx

這種解法的缺點(diǎn)顯而易見,既不美觀也不靈活。其問(wèn)題關(guān)鍵在于未將數(shù)字字符與數(shù)組aDigitCharNum下標(biāo)直接關(guān)聯(lián)起來(lái)。

以下示出更簡(jiǎn)潔的實(shí)現(xiàn)方式:

for(;dwStrIdx

上述實(shí)現(xiàn)考慮到0也為數(shù)字字符。該解法也可擴(kuò)展至統(tǒng)計(jì)所有ASCII可見字符。

1.2.2 月天校驗(yàn)

問(wèn)題:對(duì)給定年份和月份的天數(shù)進(jìn)行校驗(yàn)(需區(qū)分平年和閏年)。

普通解法主體代碼如下:

switch(OnuTime.Month)
{
case1:
case3:
case5:
case7:
case8:
case10:
case12:
if(OnuTime.Day>31||OnuTime.Day<1)
????????{
????????????CtcOamLog(FUNCTION_Pon,"Don't?support?this?Day:?%d(1~31)!!!
",?OnuTime.Day);
????????????retcode?=?S_ERROR;
????????}
????????break;
????case?2:
????????if(((OnuTime.Year%4?==?0)?&&?(OnuTime.Year%100?!=?0))?||?(OnuTime.Year%400?==?0))
????????{
????????????if(OnuTime.Day>29||OnuTime.Day<1)
????????????{
????????????????CtcOamLog(FUNCTION_Pon,"Don't?support?this?Day:?%d(1~29)!!!
",?OnuTime.Day);
????????????????retcode?=?S_ERROR;
????????????}
????????}
????????else
????????{
????????????if(OnuTime.Day>28||OnuTime.Day<1)
????????????{
????????????????CtcOamLog(FUNCTION_Pon,"Don't?support?this?Day:?%d(1~28)!!!
",?OnuTime.Day);
????????????????retcode?=?S_ERROR;
????????????}
????????}
????????break;
????case?4:
????case?6:
????case?9:
????case?11:
????????if(OnuTime.Day>30||OnuTime.Day<1)
????????{
????????????CtcOamLog(FUNCTION_Pon,"Don't?support?this?Day:?%d(1~30)!!!
",?OnuTime.Day);
????????????retcode?=?S_ERROR;
????????}
????????break;
????default:
????????CtcOamLog(FUNCTION_Pon,"Don't?support?this?Month:?%d(1~12)!!!
",?OnuTime.Month);
????????retcode?=?S_ERROR;
????????break;
}

以下示出更簡(jiǎn)潔的實(shí)現(xiàn)方式:

#defineMONTH_OF_YEAR12/*一年中的月份數(shù)*/
/*閏年:能被4整除且不能被100整除,或能被400整除*/
#defineIS_LEAP_YEAR(year)((((year)%4==0)&&((year)%100!=0))||((year)%400==0))

/*平年中的各月天數(shù),下標(biāo)對(duì)應(yīng)月份*/
INT8UaDayOfCommonMonth[MONTH_OF_YEAR]={31,28,31,30,31,30,31,31,30,31,30,31};

INT8UucMaxDay=0;
if((OnuTime.Month==2)&&(IS_LEAP_YEAR(OnuTime.Year)))
ucMaxDay=aDayOfCommonMonth[1]+1;
else
ucMaxDay=aDayOfCommonMonth[OnuTime.Month-1];

if((OnuTime.DayucMaxDay)
{
CtcOamLog(FUNCTION_Pon,"Month%ddoesn'thavethisDay:%d(1~%d)!!!
",
OnuTime.Month,OnuTime.Day,ucMaxDay);
retcode=S_ERROR;
}

1.2.3 名稱構(gòu)造

問(wèn)題:根據(jù)WAN接口承載的業(yè)務(wù)類型(Bitmap)構(gòu)造業(yè)務(wù)類型名稱字符串。

普通解法主體代碼如下:

voidSub_SetServerType(INT8U*ServerType,INT16Uwan_servertype)
{
if((wan_servertype&0x0001)==0x0001)
{
strcat(ServerType,"_INTERNET");
}
if((wan_servertype&0x0002)==0x0002)
{
strcat(ServerType,"_TR069");
}
if((wan_servertype&0x0004)==0x0004)
{
strcat(ServerType,"_VOIP");
}
if((wan_servertype&0x0008)==0x0008)
{
strcat(ServerType,"_OTHER");
}
}

以下示出C語(yǔ)言中更簡(jiǎn)潔的實(shí)現(xiàn)方式:

/*獲取var變量第bit位,編號(hào)從右至左*/
#defineGET_BIT(var,bit)(((var)>>(bit))&0x1)
constCHAR*paSvrNames[]={"_INTERNET","_TR069","_VOIP","_OTHER"};
constINT8UucSvrNameNum=sizeof(paSvrNames)/sizeof(paSvrNames[0]);

VOIDSetServerType(CHAR*pszSvrType,INT16UwSvrType)
{
INT8UucIdx=0;
for(;ucIdx

新的實(shí)現(xiàn)將數(shù)據(jù)和邏輯分離,維護(hù)起來(lái)非常方便。只要邏輯(規(guī)則)不變,則唯一可能的改動(dòng)就是數(shù)據(jù)(paSvrNames)。

1.2.4 值名解析

問(wèn)題:根據(jù)枚舉變量取值輸出其對(duì)應(yīng)的字符串,如PORT_FE(1)輸出“Fe”。

//值名映射表結(jié)構(gòu)體定義,用于數(shù)值解析器typedefstruct{
INT32UdwElem;//待解析數(shù)值,通常為枚舉變量
CHAR*pszName;//指向數(shù)值所對(duì)應(yīng)解析名字符串的指針
}T_NAME_PARSER;

/******************************************************************************
*函數(shù)名稱:NameParser
*功能說(shuō)明:數(shù)值解析器,將給定數(shù)值轉(zhuǎn)換為對(duì)應(yīng)的具名字符串
*輸入參數(shù):VOID*pvMap:值名映射表數(shù)組,含T_NAME_PARSER結(jié)構(gòu)體類型元素
VOID指針允許用戶在保持成員數(shù)目和類型不變的前提下,
定制更有意義的結(jié)構(gòu)體名和/或成員名。
INT32UdwEntryNum:值名映射表數(shù)組條目數(shù)
INT32UdwElem:待解析數(shù)值,通常為枚舉變量
INT8U*pszDefName:缺省具名字符串指針,可為空
*輸出參數(shù):NA
*返回值:INT8U*:數(shù)值所對(duì)應(yīng)的具名字符串
當(dāng)無(wú)法解析給定數(shù)值時(shí),若pszDefName為空,則返回?cái)?shù)值對(duì)應(yīng)的16進(jìn)制格式
字符串;否則返回pszDefName。
******************************************************************************/
INT8U*NameParser(VOID*pvMap,INT32UdwEntryNum,INT32UdwElem,INT8U*pszDefName)
{
CHECK_SINGLE_POINTER(pvMap,"NullPoniter");

INT32UdwEntryIdx=0;
for(dwEntryIdx=0;dwEntryIdxdwElem)
{
returnptNameParser->pszName;
}
//ANSI標(biāo)準(zhǔn)禁止對(duì)void指針進(jìn)行算法操作;GNU標(biāo)準(zhǔn)則指定void*算法操作與char*一致。
//若考慮移植性,可將pvMap類型改為INT8U*,或定義INT8U*局部變量指向pvMap。
pvMap+=sizeof(T_NAME_PARSER);
}

if(NULL!=pszDefName)
{
returnpszDefName;
}
else
{
staticINT8UszName[12]={0};//Max:"0xFFFFFFFF"
sprintf(szName,"0x%X",dwElem);
returnszName;
}
}

以下給出NameParser的簡(jiǎn)單應(yīng)用示例:
//UNI端口類型值名映射表結(jié)構(gòu)體定義
typedefstruct{
INT32UdwPortType;
INT8U*pszPortName;
}T_PORT_NAME;
//UNI端口類型解析器
T_PORT_NAMEgUniNameMap[]={
{1,"Fe"},
{3,"Pots"},
{99,"Vuni"}
};
constINT32UUNI_NAM_MAP_NUM=(INT32U)(sizeof(gUniNameMap)/sizeof(T_PORT_NAME));
VOIDNameParserTest(VOID)
{
INT8UucTestIndex=1;

printf("[%s]Result:%s!
",__FUNCTION__,ucTestIndex++,
strcmp("Unknown",NameParser(gUniNameMap,UNI_NAM_MAP_NUM,0,"Unknown"))?"ERROR":"OK");
printf("[%s]Result:%s!
",__FUNCTION__,ucTestIndex++,
strcmp("DefName",NameParser(gUniNameMap,UNI_NAM_MAP_NUM,0,"DefName"))?"ERROR":"OK");
printf("[%s]Result:%s!
",__FUNCTION__,ucTestIndex++,
strcmp("Fe",NameParser(gUniNameMap,UNI_NAM_MAP_NUM,1,"Unknown"))?"ERROR":"OK");
printf("[%s]Result:%s!
",__FUNCTION__,ucTestIndex++,
strcmp("Pots",NameParser(gUniNameMap,UNI_NAM_MAP_NUM,3,"Unknown"))?"ERROR":"OK");
printf("[%s]Result:%s!
",__FUNCTION__,ucTestIndex++,
strcmp("Vuni",NameParser(gUniNameMap,UNI_NAM_MAP_NUM,99,NULL))?"ERROR":"OK");
printf("[%s]Result:%s!
",__FUNCTION__,ucTestIndex++,
strcmp("Unknown",NameParser(gUniNameMap,UNI_NAM_MAP_NUM,255,"Unknown"))?"ERROR":"OK");
printf("[%s]Result:%s!
",__FUNCTION__,ucTestIndex++,
strcmp("0xABCD",NameParser(gUniNameMap,UNI_NAM_MAP_NUM,0xABCD,NULL))?"ERROR":"OK");
printf("[%s]Result:%s!
",__FUNCTION__,ucTestIndex++,
strcmp("NullPoniter",NameParser(NULL,UNI_NAM_MAP_NUM,0xABCD,NULL))?"ERROR":"OK");
}

gUniNameMap在實(shí)際項(xiàng)目中有十余個(gè)條目,若采用邏輯鏈實(shí)現(xiàn)將非常冗長(zhǎng)。

1.2.5 取值映射

問(wèn)題:不同模塊間同一參數(shù)枚舉值取值可能有所差異,需要適配。

此處不再給出普通的switch…case或if…else if…else結(jié)構(gòu),而直接示出以下表驅(qū)動(dòng)實(shí)現(xiàn):

typedefstruct{
PORTSTATEloopMEState;
PORTSTATEloopMIBState;
}LOOPMAPSTRUCT;

staticLOOPMAPSTRUCTs_CesLoop[]={
{NO_LOOP,e_ds1_looptype_noloop},
{PAYLOAD_LOOP,e_ds1_looptype_PayloadLoop},
{LINE_LOOP,e_ds1_looptype_LineLoop},
{PON_LOOP,e_ds1_looptype_OtherLoop},
{CES_LOOP,e_ds1_looptype_InwardLoop}};

PORTSTATEConvertLoopMEStateToMIBState(PORTSTATEvPortState)
{
INT32Unum=0,ii;

num=ARRAY_NUM(s_CesLoop);
for(ii=0;ii

相應(yīng)地,從loopMIBState映射到loopMEState需要定義一個(gè)ConvertLoopMIBStateToMEState函數(shù)。更進(jìn)一步,所有類似的一對(duì)一映射關(guān)系都必須如上的映射(轉(zhuǎn)換)函數(shù),相當(dāng)繁瑣。

事實(shí)上,從抽象層面看,該映射關(guān)系非常簡(jiǎn)單。提取共性后定義帶參數(shù)宏,如下所示:

/**********************************************************
*功能描述:進(jìn)行二維數(shù)組映射表的一對(duì)一映射,用于參數(shù)適配
*參數(shù)說(shuō)明:map --二維數(shù)組映射表
elemSrc--映射源,即待映射的元素值
elemDest--映射源對(duì)應(yīng)的映射結(jié)果
 direction --映射方向字節(jié),表示從數(shù)組哪列映射至哪列。
高4位對(duì)應(yīng)映射源列,低4位對(duì)應(yīng)映射結(jié)果列。
defaultVal--映射失敗時(shí)置映射結(jié)果為缺省值
*示例:ARRAY_MAPPER(gCesLoopMap, 3, ucLoop, 0x10, NO_LOOP);
則ucLoop=2(LINE_LOOP)
**********************************************************/
#defineARRAY_MAPPER(map,elemSrc,elemDest,direction,defaultVal)do{
INT8UucMapIdx=0,ucMapNum=0;
ucMapNum=sizeof(map)/sizeof(map[0]);
for(ucMapIdx=0;ucMapIdx>4])
{
elemDest=map[ucMapIdx][(direction)&0x0F];
break;
}
}
if(ucMapIdx==ucMapNum)
{
elemDest=(defaultVal);
}
}while(0)

參數(shù)取值轉(zhuǎn)換時(shí)直接調(diào)用統(tǒng)一的映射器宏,如下:

staticINT8UgCesLoopMap[][2]={
{NO_LOOP,e_ds1_looptype_noloop},
{PAYLOAD_LOOP,e_ds1_looptype_PayloadLoop},
{LINE_LOOP,e_ds1_looptype_LineLoop},
{PON_LOOP,e_ds1_looptype_OtherLoop},
{CES_LOOP,e_ds1_looptype_InwardLoop}};

ARRAY_MAPPER(gCesLoopMap,tPara.dwParaVal[0],dwLoopConf,0x01,e_ds1_looptype_noloop);
另舉一例:

#defineCES_DEFAULT_JITTERBUF(INT32U)2000/*默認(rèn)jitterbuf為2000us,而1幀=125us*/
#defineCES_JITTERBUF_STEP(INT32U)125/*jitterbuf步長(zhǎng)為125us,即1幀*/
#defineCES_DEFAULT_QUEUESIZE(INT32U)5
#defineCES_DEFAULT_MAX_QUEUESIZE(INT32U)7

#defineARRAY_NUM(array)(sizeof(array)/sizeof((array)[0]))/*數(shù)組元素個(gè)數(shù)*/
typedefstruct{
INT32UdwJitterBuffer;
INT32UdwFramePerPkt;
INT32UdwQueueSize;
}QUEUE_SIZE_MAP;
/*gCesQueueSizeMap也可以(JitterBuffer/FramePerPkt)值為索引,更加緊湊*/
staticQUEUE_SIZE_MAPgCesQueueSizeMap[]={
{1,1,1},{1,2,1},{2,1,2},{2,2,1},
{3,1,3},{3,2,1},{4,1,3},{4,2,1},
{5,1,4},{5,2,3},{6,1,4},{6,2,3},
{7,1,4},{7,2,3},{8,1,4},{8,2,3},
{9,1,5},{9,2,4},{10,1,5},{10,2,4},
{11,1,5},{11,2,4},{12,1,5},{12,2,4},
{13,1,5},{13,2,4},{14,1,5},{14,2,4},
{15,1,5},{15,2,4},{16,1,5},{16,2,4},
{17,1,6},{17,2,5},{18,1,6},{18,2,5},
{19,1,6},{19,2,5},{20,1,6},{20,2,5},
{21,1,6},{21,2,5},{22,1,6},{22,2,5},
{23,1,6},{23,2,5},{24,1,6},{24,2,5},
{25,1,6},{25,2,5},{26,1,6},{26,2,5},
{27,1,6},{27,2,5},{28,1,6},{28,2,5},
{29,1,6},{29,2,5},{30,1,6},{30,2,5},
{31,1,6},{31,2,5},{32,1,6},{32,2,5}};
/**********************************************************
*函數(shù)名稱:CalcQueueSize
*功能描述:根據(jù)JitterBuffer和FramePerPkt計(jì)算QueueSize
*注意事項(xiàng):配置的最大緩存深度
*=2*JitterBuffer/FramePerPkt
*=2*NPacket=2^QueueSize
*JitterBuffer為125us幀速率的倍數(shù),
*FramePerPkt為每個(gè)分組的幀數(shù),
* QueueSize向上取整,最大為7。
**********************************************************/
INT32UCalcQueueSize(INT32UdwJitterBuffer,INT32UdwFramePerPkt)
{
INT8UucIdx=0,ucNum=0;

//本函數(shù)暫時(shí)僅考慮E1
ucNum=ARRAY_NUM(gCesQueueSizeMap);
for(ucIdx=0;ucIdx

1.2.6 版本控制

問(wèn)題:控制OLT與ONU之間的版本協(xié)商。ONU本地設(shè)置三比特控制字,其中bit2(MSB)~bit0(LSB)分別對(duì)應(yīng)0x21、0x30和0xAA版本號(hào);且bitX為0表示上報(bào)對(duì)應(yīng)版本號(hào),bitX為1表示不上報(bào)對(duì)應(yīng)版本號(hào)。其他版本號(hào)如0x20、0x13和0x1必須上報(bào),即不受控制。

最初的實(shí)現(xiàn)采用if…else if…else結(jié)構(gòu),代碼非常冗長(zhǎng),如下:

pstSendTlv->ucLength=0x1f;
if(gOamCtrlCode==0)
{
vosMemCpy(pstSendTlv->aucVersionList,ctc_oui,3);
pstSendTlv->aucVersionList[3]=0x30;
vosMemCpy(&(pstSendTlv->aucVersionList[4]),ctc_oui,3);
pstSendTlv->aucVersionList[7]=0x21;
vosMemCpy(&(pstSendTlv->aucVersionList[8]),ctc_oui,3);
pstSendTlv->aucVersionList[11]=0x20;
vosMemCpy(&(pstSendTlv->aucVersionList[12]),ctc_oui,3);
pstSendTlv->aucVersionList[15]=0x13;
vosMemCpy(&(pstSendTlv->aucVersionList[16]),ctc_oui,3);
pstSendTlv->aucVersionList[19]=0x01;
vosMemCpy(&(pstSendTlv->aucVersionList[20]),ctc_oui,3);
pstSendTlv->aucVersionList[23]=0xaa;
}
elseif(gOamCtrlCode==1)
{
vosMemCpy(pstSendTlv->aucVersionList,ctc_oui,3);
pstSendTlv->aucVersionList[3]=0x30;
vosMemCpy(&(pstSendTlv->aucVersionList[4]),ctc_oui,3);
pstSendTlv->aucVersionList[7]=0x21;
vosMemCpy(&(pstSendTlv->aucVersionList[8]),ctc_oui,3);
pstSendTlv->aucVersionList[11]=0x20;
vosMemCpy(&(pstSendTlv->aucVersionList[12]),ctc_oui,3);
pstSendTlv->aucVersionList[15]=0x13;
vosMemCpy(&(pstSendTlv->aucVersionList[16]),ctc_oui,3);
pstSendTlv->aucVersionList[19]=0x01;
}
//此處省略gOamCtrlCode==2~6的處理代碼
elseif(gOamCtrlCode==7)
{
vosMemCpy(&(pstSendTlv->aucVersionList),ctc_oui,3);
pstSendTlv->aucVersionList[3]=0x20;
vosMemCpy(&(pstSendTlv->aucVersionList[4]),ctc_oui,3);
pstSendTlv->aucVersionList[7]=0x13;
vosMemCpy(&(pstSendTlv->aucVersionList[8]),ctc_oui,3);
pstSendTlv->aucVersionList[11]=0x01;
}

以下示出C語(yǔ)言中更簡(jiǎn)潔的實(shí)現(xiàn)方式(基于二維數(shù)組):
/**********************************************************************
*版本控制字?jǐn)?shù)組定義
* gOamCtrlCode: Bitmap控制字。Bit-X為0時(shí)上報(bào)對(duì)應(yīng)版本,Bit-X為1時(shí)屏蔽對(duì)應(yīng)版本。
* CTRL_VERS_NUM:可控版本個(gè)數(shù)。
* CTRL_CODE_NUM:控制字個(gè)數(shù)。與CTRL_VERS_NUM有關(guān)。
* gOamVerCtrlMap:版本控制字?jǐn)?shù)組。行對(duì)應(yīng)控制字,列對(duì)應(yīng)可控版本。
元素值為0時(shí)不上報(bào)對(duì)應(yīng)版本,元素值非0時(shí)上報(bào)該元素值。
* Note:該數(shù)組旨在實(shí)現(xiàn)“數(shù)據(jù)與控制隔離”。后續(xù)若要新增可控版本,只需修改
--CTRL_VERS_NUM
--gOamVerCtrlMap新增行(控制字)
--gOamVerCtrlMap新增列(可控版本)
**********************************************************************/
#defineCTRL_VERS_NUM3
#defineCTRL_CODE_NUM(1<aucVersionList[index],ctc_oui,3);
index+=3;
pstSendTlv->aucVersionList[index++]=gOamVerCtrlMap[gOamCtrlCode][verIdx];
}
}
vosMemCpy(&pstSendTlv->aucVersionList[index],ctc_oui,3);
index+=3;
pstSendTlv->aucVersionList[index++]=0x20;
vosMemCpy(&pstSendTlv->aucVersionList[index],ctc_oui,3);
index+=3;
pstSendTlv->aucVersionList[index++]=0x13;
vosMemCpy(&pstSendTlv->aucVersionList[index],ctc_oui,3);
index+=3;
pstSendTlv->aucVersionList[index++]=0x01;

pstSendTlv->ucLength=INFO_TYPE_VERS_LEN+index;

1.2.7 消息處理

問(wèn)題:終端輸入不同的打印命令,調(diào)用相應(yīng)的打印函數(shù),以控制不同級(jí)別的打印。這是一段消息(事件)驅(qū)動(dòng)程序。本模塊接收其他模塊(如串口驅(qū)動(dòng))發(fā)送的消息,根據(jù)消息中的打印級(jí)別字符串和開關(guān)模式,調(diào)用不同函數(shù)進(jìn)行處理。常見的實(shí)現(xiàn)方法如下:

voidlogall(void)
{
g_log_control[0]=0xFFFFFFFF;
}

voidnoanylog(void)
{
g_log_control[0]=0;
}

voidlogOam(void)
{
g_log_control[0]|=(0x01<

以下示出C語(yǔ)言中更簡(jiǎn)潔的實(shí)現(xiàn)方式:

typedefstruct{
OAM_LOG_OFF=(INT8U)0,
OAM_LOG_ON=(INT8U)1
}E_OAM_LOG_MODE;
typedefFUNC_STATUS(*OamLogHandler)(VOID);
typedefstruct{
CHAR*pszLogCls;/*打印級(jí)別*/
E_OAM_LOG_MODEeLogMode;/*打印模式*/
OamLogHandlerfnLogHandler;/*打印函數(shù)*/
}T_OAM_LOG_MAP;

T_OAM_LOG_MAPgOamLogMap[]={
{"all",OAM_LOG_OFF,noanylog},
{"oam",OAM_LOG_OFF,nologOam},
//......
{"version",OAM_LOG_OFF,nologVersion},

{"all",OAM_LOG_ON,logall},
{"oam",OAM_LOG_ON,logOam},
//......
{"version",OAM_LOG_ON,logVersion}
};
INT32UgOamLogMapNum=sizeof(gOamLogMap)/sizeof(T_OAM_LOG_MAP);

VOIDlogExec(CHAR*pszName,INT8UucSwitch)
{
INT8UucIdx=0;
for(;ucIdx

這種表驅(qū)動(dòng)消息處理實(shí)現(xiàn)的優(yōu)點(diǎn)如下:

1. 增強(qiáng)可讀性,消息如何處理從表中一目了然。

2. 增強(qiáng)可擴(kuò)展性。更容易修改,要增加新的消息,只要修改數(shù)據(jù)即可,不需要修改流程。

3. 降低復(fù)雜度。通過(guò)把程序邏輯的復(fù)雜度轉(zhuǎn)移到人類更容易處理的數(shù)據(jù)中來(lái),從而達(dá)到控制復(fù)雜度的目標(biāo)。

4. 主干清晰,代碼重用。

若各索引為順序枚舉值,則建立多維數(shù)組(每維對(duì)應(yīng)一個(gè)索引),根據(jù)下標(biāo)直接定位到處理函數(shù),效率會(huì)更高。

注意,考慮到本節(jié)實(shí)例中l(wèi)ogOam/logPon或nologOam/nologPon等函數(shù)本質(zhì)上是基于打印級(jí)別的比特操作,因此可進(jìn)一步簡(jiǎn)化。以下例舉其相似實(shí)現(xiàn):

/*日志控制類型定義*/
typedefenum
{
LOG_NORM=0,/*未分類日志,可用于通用日志*/
LOG_FRM,/*Frame,OMCI幀日志*/
LOG_PON,/*Pon,光鏈路相關(guān)日志*/
LOG_ETH,/*Ethernet,Layer2以太網(wǎng)日志*/
LOG_NET,/*Internet,Layer3網(wǎng)絡(luò)日志*/
LOG_MULT,/*Multicast,組播日志*/
LOG_QOS,/*QOS,流量日志*/
LOG_CES,/*Ces,TDM電路仿真日志*/
LOG_VOIP,/*Voip,語(yǔ)音日志*/
LOG_ALM,/*Alarm,告警日志*/
LOG_PERF,/*Performance,性能統(tǒng)計(jì)日志*/
LOG_VER,/*Version,軟件升級(jí)日志*/
LOG_XDSL,/*xDsl日志*/
LOG_DB,/*數(shù)據(jù)庫(kù)操作日志*/
//新日志類型在此處擴(kuò)展,共支持32種日志類型
LOG_ALL=UINT_MAX/*所有日志類型*/
}E_LOG_TYPE;

/*****************************************************************************
*變量名稱:gOmciLogCtrl
*作用描述:OMCI日志控制字,BitMap格式(比特編號(hào)從LSB至MSB依次為Bit0->BitN)。
*Bit0~N分別對(duì)應(yīng)E_LOG_TYPE各枚舉值(除LOG_ALL外)。
*BitX為0時(shí)關(guān)閉日志類型對(duì)應(yīng)的日志功能,BitX為1時(shí)則予以打開。
*變量范圍:該變量為四字節(jié)整型靜態(tài)全局變量,即支持32種日志類型。
*訪問(wèn)說(shuō)明:通過(guò)GetOmciLogCtrl/SetOmciLogCtrl/OmciLogCtrl函數(shù)訪問(wèn)/設(shè)置控制字。
*****************************************************************************/
staticINT32UgOmciLogCtrl=0;

//日志類型字符串?dāng)?shù)組,下標(biāo)為各字符串所對(duì)應(yīng)的日志類型枚舉值。
staticconstINT8U*paLogTypeName[]={
"Norm","Frame","Pon","Ethernet","Internet",
"Multicast","Qos","Ces","Voip","Alarm",
"Performance","Version","Xdsl","Db"
};
staticconstINT8UucLogTypeNameNum=sizeof(paLogTypeName)/sizeof(paLogTypeName[0]);

staticVOIDSetGlobalLogCtrl(E_LOG_TYPEeLogType,INT8UucLogSwitch)
{
if(LOG_ON==ucLogSwitch)
gOmciLogCtrl=LOG_ALL;
else
gOmciLogCtrl=0;
}
staticVOIDSetSpecificLogCtrl(E_LOG_TYPEeLogType,INT8UucLogSwitch)
{
if(LOG_ON==ucLogSwitch)
SET_BIT(gOmciLogCtrl,eLogType);
else
CLR_BIT(gOmciLogCtrl,eLogType);
}

VOIDOmciLogCtrl(CHAR*pszLogType,INT8UucLogSwitch)
{
if(0==strncasecmp(pszLogType,"All",LOG_TYPE_CMP_LEN))
{
SetGlobalLogCtrl(LOG_ALL,ucLogSwitch);
return;
}

INT8UucIdx=0;
for(ucIdx=0;ucIdx

2. 編程思想

表驅(qū)動(dòng)法屬于數(shù)據(jù)驅(qū)動(dòng)編程的一種,其核心思想在《Unix編程藝術(shù)》和《代碼大全2》中均有闡述。兩者均認(rèn)為人類閱讀復(fù)雜數(shù)據(jù)結(jié)構(gòu)遠(yuǎn)比復(fù)雜的控制流程容易,即相對(duì)于程序邏輯,人類更擅長(zhǎng)于處理數(shù)據(jù)。

本節(jié)將由Unix設(shè)計(jì)原則中的“分離原則”和“表示原則”展開。

分離原則:策略同機(jī)制分離,接口同引擎分離

機(jī)制即提供的功能;策略即如何使用功能。

策略的變化要遠(yuǎn)遠(yuǎn)快于機(jī)制的變化。將兩者分離,可以使機(jī)制相對(duì)保持穩(wěn)定,而同時(shí)支持策略的變化。

代碼大全中提到“隔離變化”的概念,以及設(shè)計(jì)模式中提到的將易變化的部分和不易變化的部分分離也是這個(gè)思路。

表示原則:把知識(shí)疊入數(shù)據(jù)以求邏輯質(zhì)樸而健壯

即使最簡(jiǎn)單的程序邏輯讓人類來(lái)驗(yàn)證也很困難,但就算是很復(fù)雜的數(shù)據(jù),對(duì)人類來(lái)說(shuō),還是相對(duì)容易推導(dǎo)和建模的。數(shù)據(jù)比編程邏輯更容易駕馭。在復(fù)雜數(shù)據(jù)和復(fù)雜代碼中選擇,寧可選擇前者。更進(jìn)一步,在設(shè)計(jì)中,應(yīng)該主動(dòng)將代碼的復(fù)雜度轉(zhuǎn)移到數(shù)據(jù)中去(參考“版本控制”)。

在“消息處理”示例中,每個(gè)消息處理的邏輯不變,但消息可能是變化的。將容易變化的消息和不容易變化的查找邏輯分離,即“隔離變化”。此外,該例也體現(xiàn)消息內(nèi)部的處理邏輯(機(jī)制)和不同的消息處理(策略)分離。

數(shù)據(jù)驅(qū)動(dòng)編程可以應(yīng)用于:

1.函數(shù)級(jí)設(shè)計(jì),如本文示例。2.程序級(jí)設(shè)計(jì),如用表驅(qū)動(dòng)法實(shí)現(xiàn)狀態(tài)機(jī)。3.系統(tǒng)級(jí)設(shè)計(jì),如DSL。

注意,數(shù)據(jù)驅(qū)動(dòng)編程不是全新的編程模型,只是一種設(shè)計(jì)思路,在Unix/Linux開源社區(qū)應(yīng)用很多。數(shù)據(jù)驅(qū)動(dòng)編程中,數(shù)據(jù)不但表示某個(gè)對(duì)象的狀態(tài),實(shí)際上還定義程序的流程,這點(diǎn)不同于面向?qū)ο笤O(shè)計(jì)中的數(shù)據(jù)“封裝”。

3. 附錄

3.1 網(wǎng)友觀點(diǎn)

Booch的《面向?qū)ο蠓治雠c設(shè)計(jì)》一書中,提到所有的程序設(shè)計(jì)語(yǔ)言大概有3個(gè)源流:結(jié)構(gòu)化編程;面向?qū)ο缶幊?;?shù)據(jù)驅(qū)動(dòng)編程。

我認(rèn)為數(shù)據(jù)驅(qū)動(dòng)編程的本質(zhì)是“參數(shù)化抽象”的思想,不同于OO的“規(guī)范化抽象”的思想。

數(shù)據(jù)驅(qū)動(dòng)編程在網(wǎng)絡(luò)游戲開發(fā)過(guò)程中很常用,但是少有人專門提到這個(gè)詞。

數(shù)據(jù)驅(qū)動(dòng)編程有很多名字:元編程,解釋器/虛擬機(jī),LOP/微語(yǔ)言/DSL等。包括聲明式編程、標(biāo)記語(yǔ)言、甚至所見即所得的拖放控件,都算是數(shù)據(jù)驅(qū)動(dòng)編程的一種吧。

數(shù)據(jù)驅(qū)動(dòng)編程可以幫助處理復(fù)雜性,和結(jié)構(gòu)化編程、OO 均可相容。(正交的角度)將變和不變的部分分離,策略和機(jī)制分離,由此聯(lián)想到的還有:(數(shù)據(jù)和代碼的分離,微語(yǔ)言和解釋器的分離,被生成代碼和代碼生成器的分離);更近一步:(微內(nèi)核插件式體系結(jié)構(gòu))

元編程應(yīng)該說(shuō)是更加泛化的數(shù)據(jù)驅(qū)動(dòng)編程,元編程不是新加入一個(gè)間接層,而是退居一步,使得當(dāng)前的層變成一個(gè)間接層。元編程分為靜態(tài)元編程(編譯時(shí))和動(dòng)態(tài)元編程(運(yùn)行時(shí)),靜態(tài)元編程本質(zhì)上是一種 代碼生成技術(shù)或者編譯器技術(shù);動(dòng)態(tài)元編程一般通過(guò)解釋器(或虛擬機(jī))加以實(shí)現(xiàn)。

數(shù)據(jù)驅(qū)動(dòng)編程當(dāng)然也不應(yīng)該說(shuō)是“反抽象的”,但的確與“OO抽象”的思維方式是迥然不同,涇渭分明的,如TAOUP一書中所述:“在Unix的模塊化傳統(tǒng)和圍繞OO語(yǔ)言發(fā)展起來(lái)的使用模式之間,存在著緊張的對(duì)立關(guān)系”應(yīng)該說(shuō)數(shù)據(jù)驅(qū)動(dòng)編程的思路與結(jié)構(gòu)化編程和OO是正交的,更類似一種“跳出三界外,不在五行中”的做法。

編程和人的關(guān)系

人類心智的限制,一切的背后都有人的因素作為依據(jù):

a.人同時(shí)關(guān)注的信息數(shù)量:7+-2 (所以要分模塊)

b.人接收一組新信息的平均時(shí)間5s (所以要簡(jiǎn)單,系統(tǒng)總的模塊數(shù)不要太多)

c.人思維的直觀性(人的視覺(jué)能力和模糊思維能力),這意味這兩點(diǎn):A “直”——更善于思考自己能直接接觸把玩的東西;(所以要“淺平透”、使用具象的設(shè)計(jì),要盡量代碼中只有順直的流程),B “觀”——更善于觀圖而不是推算邏輯;(所以要表驅(qū)動(dòng)法,數(shù)據(jù)驅(qū)動(dòng)編程,要UML,要可視化編程——當(dāng)然MDA是太理想化了)

d.人不能持續(xù)集中注意力(人在一定的代碼行數(shù)中產(chǎn)生的bug數(shù)量的比例是一定的,所以語(yǔ)言有具有表現(xiàn)力,要體現(xiàn)表達(dá)的經(jīng)濟(jì)性)所以要機(jī)制與策略分離,要數(shù)據(jù)和代碼分離(數(shù)據(jù)驅(qū)動(dòng)編程),要微語(yǔ)言,要DSL,要LOP……

e.人是有創(chuàng)造欲,有現(xiàn)實(shí)利益心的(只要偶可能總是不夠遵從規(guī)范,或想創(chuàng)造規(guī)范謀利——只要成本能承受,在硬件領(lǐng)域就不行)

另外,開一個(gè)有意思的玩笑,Unix編程藝術(shù)藝術(shù)的英文縮寫為TAOUP,我覺(jué)得可以理解為UP之TAO——向上拋出之道——將復(fù)雜的易變的邏輯作為數(shù)據(jù)或更高層代碼拋給上層!

3.2 函數(shù)指針

“消息處理”一節(jié)示例中的函數(shù)指針有點(diǎn)插件結(jié)構(gòu)的味道??蓪?duì)這些插件進(jìn)行方便替換,新增,刪除,從而改變程序的行為。而這種改變,對(duì)事件處理函數(shù)的查找又是隔離的(隔離變化)。

函數(shù)指針?lè)浅S杏?,但使用時(shí)需注意其缺陷:無(wú)法檢查參數(shù)(parameter)和返回值(return value)的類型。因?yàn)楹瘮?shù)已經(jīng)退化成指針,而指針不攜帶這些類型信息。缺少類型檢查,當(dāng)參數(shù)或返回值不一致時(shí),可能會(huì)造成嚴(yán)重的錯(cuò)誤。

例如,定義三個(gè)函數(shù),分別具有兩個(gè)參數(shù):

intmax(intx,inty){returnx>y?x:y;}
intmin(intx,inty){returnx





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7610

    瀏覽量

    137232
  • 編程語(yǔ)言
    +關(guān)注

    關(guān)注

    10

    文章

    1947

    瀏覽量

    34845
  • WAN接口
    +關(guān)注

    關(guān)注

    0

    文章

    10

    瀏覽量

    6838

原文標(biāo)題:C語(yǔ)言的驅(qū)動(dòng)法編程詳細(xì)解析(超多代碼案例)

文章出處:【微信號(hào):mcu168,微信公眾號(hào):硬件攻城獅】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    C語(yǔ)言驅(qū)動(dòng)編程詳細(xì)解析

    數(shù)據(jù)壓倒一切。如果選擇了正確的數(shù)據(jù)結(jié)構(gòu)并把一切組織的井井有條,正確的算法就不言自明。編程的核心是數(shù)據(jù)結(jié)構(gòu),而不是算法。
    發(fā)表于 01-13 10:44 ?529次閱讀

    嵌入式c語(yǔ)言編程(由淺入深)

    本內(nèi)容詳細(xì)介紹了嵌入式c語(yǔ)言編程的各項(xiàng)知識(shí),包括嵌入式c語(yǔ)言
    發(fā)表于 11-02 14:37 ?0次下載
    嵌入式<b class='flag-5'>c</b><b class='flag-5'>語(yǔ)言</b><b class='flag-5'>編程</b>(由淺入深)

    STM8的C語(yǔ)言編程說(shuō)明

    STM8的C語(yǔ)言編程說(shuō)明STM8的C語(yǔ)言編程說(shuō)明STM8的C
    發(fā)表于 12-10 16:19 ?37次下載

    C語(yǔ)言入門經(jīng)典-C語(yǔ)言編程

    C語(yǔ)言入門經(jīng)典-C語(yǔ)言編程,感興趣的可以看看哦。
    發(fā)表于 08-16 18:54 ?126次下載

    TMS320C54xC語(yǔ)言編程和運(yùn)行環(huán)境的詳細(xì)中文資料概述

    本文的介紹了TI的產(chǎn)品TMS320C54xC語(yǔ)言編程和運(yùn)行環(huán)境的詳細(xì)中文資料概述主要內(nèi)容包括了TMS320C54x
    發(fā)表于 05-08 14:44 ?18次下載
    TMS320<b class='flag-5'>C</b>54xC<b class='flag-5'>語(yǔ)言</b><b class='flag-5'>編程</b>和運(yùn)行環(huán)境的<b class='flag-5'>詳細(xì)</b>中文資料概述

    華為的C語(yǔ)言編程規(guī)范的詳細(xì)資料說(shuō)明

    本文檔詳細(xì)介紹的是華為技術(shù)有限公司的C語(yǔ)言編程規(guī)范的詳細(xì)資料說(shuō)明。本規(guī)范制定了編寫C
    發(fā)表于 03-06 08:00 ?31次下載
    華為的<b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b><b class='flag-5'>編程</b>規(guī)范的<b class='flag-5'>詳細(xì)</b>資料說(shuō)明

    單片機(jī)C語(yǔ)言編程的關(guān)鍵字詳細(xì)說(shuō)明

    本文檔的主要內(nèi)容詳細(xì)介紹的是單片機(jī)C語(yǔ)言編程的關(guān)鍵字詳細(xì)說(shuō)明。
    發(fā)表于 12-10 17:32 ?23次下載
    單片機(jī)<b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b><b class='flag-5'>編程</b>的關(guān)鍵字<b class='flag-5'>詳細(xì)</b>說(shuō)明

    Linux下C語(yǔ)言編程入門教程詳細(xì)說(shuō)明

    本文是Linux 下C 語(yǔ)言編程入門教程。主要介紹了Linux 的發(fā)展與特點(diǎn)、C語(yǔ)言的基礎(chǔ)知識(shí)、Linux 程序設(shè)計(jì)基礎(chǔ)知識(shí)及其下
    發(fā)表于 08-25 18:05 ?39次下載
    Linux下<b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b><b class='flag-5'>編程</b>入門教程<b class='flag-5'>詳細(xì)</b>說(shuō)明

    SPI總線驅(qū)動(dòng)C語(yǔ)言源代碼詳細(xì)概述

    本文檔的主要內(nèi)容詳細(xì)介紹的是SPI總線驅(qū)動(dòng)C語(yǔ)言源代碼詳細(xì)概述。
    的頭像 發(fā)表于 09-26 11:36 ?7302次閱讀

    C語(yǔ)言驅(qū)動(dòng)編程的代碼案例

    是穩(wěn)定的。 本文例舉的編程實(shí)現(xiàn)多為代碼片段,但不影響描述的完整性。 本文例舉的編程雖然基于C語(yǔ)言,但其編程思想也適用于其他
    的頭像 發(fā)表于 10-12 09:21 ?2013次閱讀

    單片機(jī)c語(yǔ)言+編程c語(yǔ)言_C編程語(yǔ)言簡(jiǎn)介

    單片機(jī)c語(yǔ)言+編程c語(yǔ)言In this tutorial you will get basic introduction to
    發(fā)表于 11-29 10:21 ?38次下載
    單片機(jī)<b class='flag-5'>c</b><b class='flag-5'>語(yǔ)言</b>+<b class='flag-5'>編程</b><b class='flag-5'>c</b><b class='flag-5'>語(yǔ)言</b>_<b class='flag-5'>C</b><b class='flag-5'>編程</b><b class='flag-5'>語(yǔ)言</b>簡(jiǎn)介

    C語(yǔ)言驅(qū)動(dòng)編程詳細(xì)解析分享

    使用表驅(qū)動(dòng)時(shí)需要關(guān)注兩個(gè)問(wèn)題:一是如何查表,從表中讀取正確的數(shù)據(jù);二是表里存放什么,如數(shù)值或函數(shù)指針。前者參見1.1節(jié)“查表方式”內(nèi)容,后者參見1.2節(jié)“實(shí)戰(zhàn)示例”內(nèi)容。
    的頭像 發(fā)表于 02-20 09:20 ?645次閱讀

    基于C語(yǔ)言驅(qū)動(dòng)編程代碼分析

    所謂表驅(qū)動(dòng)(Table-Driven Approach)簡(jiǎn)而言之就是用查表的方法獲取數(shù)據(jù)。此處的“表”通常為數(shù)組,但可視為數(shù)據(jù)庫(kù)的一種體現(xiàn)。
    發(fā)表于 02-20 09:20 ?362次閱讀

    深入解析C語(yǔ)言驅(qū)動(dòng)編程實(shí)例

    所謂表驅(qū)動(dòng)(Table-Driven Approach)簡(jiǎn)而言之就是用查表的方法獲取數(shù)據(jù)。此處的“表”通常為數(shù)組,但可視為數(shù)據(jù)庫(kù)的一種體現(xiàn)。
    發(fā)表于 04-23 18:16 ?342次閱讀

    PLC編程語(yǔ)言C語(yǔ)言的區(qū)別

    在工業(yè)自動(dòng)化和計(jì)算機(jī)編程領(lǐng)域中,PLC(可編程邏輯控制器)編程語(yǔ)言C語(yǔ)言各自扮演著重要的角色。
    的頭像 發(fā)表于 06-14 17:11 ?3045次閱讀