Here's a look at the use of arrays of function pointers in C/C++ as jump ... the function that uses it–and thus keeping it off the stack.
Home
Home
Bloggers
MichaelBarr
NigelJones
MiroSamek
PostsbyCategory
NewsletterSignup
AboutUs
ContactUs
Login
Searchfor:
«InPraiseoftheCPreprocessor’s#errorDirective
RS-485TransmitEnableSignalControl»
JumpTablesviaFunctionPointerArraysinC/C++
Thursday,December17th,2009byNigelJones
AlsoavailableinPDFversion.
Jumptables,alsocalledbranchtables,areanefficientmeansofhandlingsimilareventsinsoftware.Here’salookattheuseofarraysoffunctionpointersinC/C++asjumptables.
Examinationofassemblylanguagecodethathasbeencraftedbyanexpertwillusuallyrevealextensiveuseoffunction“branchtables.”Branchtables(a.k.a.,jumptables)areusedbecausetheyofferauniqueblendofcompactnessandexecutionspeed,particularlyonmicroprocessorsthatsupportindexedaddressing.WhenoneexaminestypicalC/C++code,however,thebranchtable(i.e.,anarrayoffuntionpointers)isamuchrarerbeast.ThepurposeofthisarticleistoexaminewhybranchtablesarenotusedbyC/C++programmersandtomakethecasefortheirextensiveuse.Realworldexamplesoftheiruseareincluded.
Functionpointers
IntalkingtoC/C++programmersaboutthistopic,threereasonsareusuallycitedfornotusingfunctionpointers.Theyare:
Theyaredangerous
Agoodoptimizingcompilerwillgenerateajumptablefromaswitchstatement,soletthecompilerdothework
Theyaretoodifficulttocodeandmaintain
Arefunctionpointersdangerous?
Thisschoolofthoughtcomesabout,becausecodethatindexesintoatableandthencallsafunctionbasedontheindexhasthecapabilitytoendupjustaboutanywhere.Forinstance,considerthefollowingcodefragment:
void(*pf[])(void)={fna,fnb,fnc,…,fnz};
voidtest(constINTjump_index)
{
/*Callthefunctionspecifiedbyjump_index*/
pf[jump_index]();
}
Theabovecodedeclarespf[]tobeanarrayofpointerstofunctions,eachofwhichtakesnoargumentsandreturnsvoid.Thetest()functionsimplycallsthespecifiedfunctionviathearray.Asitstands,thiscodeisdangerousforthefollowingreasons.
pf[]isaccessiblebyanyone
Intest(),thereisnoboundschecking,suchthatanerroneousjump_indexwouldspelldisaster
Amuchbetterwaytocodethisthatavoidstheseproblemsisasfollows
voidtest(uint8_tconstump_index)
{
staticvoid(*pf[])(void)={fna,fnb,fnc,…,fnz};
if(jump_indexinterval!=0;ptr++)
{
if(!(time%ptr->interval))
{
/*Timetocallthefunction*/
(ptr->proc)();
}
}
}
}
}
Inthiscase,wedefineourowndatatype(TIMED_TASK)thatconsistssimplyofanintervalandapointertoafunction.WethendefineanarrayofTIMED_TASK,andinitializeitwiththelistoffunctionsthataretobecalledandtheircallinginterval.Inmain(),wehavethestartupcodewhichmustenableaperiodictimerinterruptthatincrementsthevolatilevariabletickatafixedinterval.Wethenentertheinfiniteloop.
Theinfiniteloopchecksforanon-zerotickvalue,decrementsthetickvariableandcomputestheelapsedtimesincetheprogramstartedrunning.Thecodethensimplystepsthrougheachofthetasks,toseewhetheritistimeforthatonetobeexecutedand,ifso,callsitviathefunctionpointer.
Ifyourapplicationonlyconsistsoftwoorthreetasks,thenthisapproachisprobablyoverkill.However,ifyourprojecthasalargenumberoftimedtasks,oritislikelythatyouwillhavetoaddtasksinthefuture,thenthisapproachisratherpalatable.Notethataddingtasksand/orchangingintervalssimplyrequireseditingofthetimed_task[]array.Nocode,perse,hastobechanged.
Interruptvectortables
Thefourthapplicationoffunctionjumptablesisthearrayofinterruptvectors.Onmostprocessors,theinterruptvectorsareincontiguouslocations,witheachvectorrepresentingapointertoaninterruptserviceroutinefunction.Dependinguponthecompiler,theworkmaybedoneforyouimplicitly,oryoumaybeforcedtogeneratethefunctiontable.Inthelattercase,implementingthevectorsviaaswitchstatementwillnotwork!
Hereisthevectortablefromtheindustrialpowersupplyprojectmentionedabove.ThisprojectwasimplementedusingaWhitesmiths’compileranda68HC11microncontroller.
IMPORTVOID_stext();/*68HC11-specificstartuproutine*/
staticVOID(*const_vectab[])()=
{
SCI_Interrupt, /*SCI*/
badSPI_Interrupt, /*SPI*/
badPAI_Interrupt, /*Pulseaccinput*/
badPAO_Interrupt, /*Pulseaccoverf*/
badTO_Interrupt, /*Timeroverf*/
badOC5_Interrupt, /*Outputcompare5*/
badOC4_Interrupt, /*Outputcompare4*/
badOC3_Interrupt, /*Outputcompare3*/
badOC2_Interrupt, /*Outputcompare2*/
badOC1_Interrupt, /*Outputcompare1*/
badIC3_Interrupt, /*Inputcapture3*/
badIC2_Interrupt, /*Inputcapture2*/
badIC1_Interrupt, /*Inputcapture1*/
RTI_Interrupt, /*Realtime*/
Uart_Interrupt, /*IRQ*/
PFI_Interrupt, /*XIRQ*/
badSWI_Interrupt, /*SWI*/
IlOpC_Interrupt, /*illegal*/
_stext, /*copfail*/
_stext, /*copclockfail*/
_stext, /*RESET*/
};
Acoupleofpointsareworthmaking:
Theaboveisinsufficienttolocatethetablecorrectlyinmemory.Thishastobedonevialinkerdirectives.
Notethatunusedinterruptsstillhaveanentryinthetable.Doingsoensuresthatthetableiscorrectlyalignedandtrapscanbeplacedonunexpectedinterrupts.
Ifanyoftheseexampleshaswhetyourappetiteforusingarraysoffunctionpointers,butyouarestilluncomfortablewiththedeclarationcomplexity,thenfearnot!Youwillfindavarietyofdeclarations,rangingfromthestraightforwardtothedownrightappallingbelow.Theexamplesareallreasonablypracticalinthesensethatthedesiredfunctionalityisnotoutlandish(thatis,therearenodeclarationsforarraysofpointerstofunctionsthattakepointerstoarraysoffunctionpointersandsoon).
Declarationandusehints
AlloftheexamplesbelowadheretoconventionsthatIhavefoundtobeusefulovertheyears,specifically:
1.Alloftheexamplesareprecededbystatic.Thisisdoneontheassumptionthatthescopeofafunctiontableshouldbehighlylocalized,ideallywithinanenclosingfunction.
2.Ineveryexamplethearraypf[]isalsoprecededwithconst.Thisdeclaresthatthepointersinthearraycannotbemodifiedafterinitialization.Thisisthenormal(andsafe)usagescenario.
3.Therearetwosyntacticallydifferentwaysofinvokingafunctionviaapointer.Ifwehaveafunctionpointerwiththedeclaration:
void(*fnptr)(int); /*fnptrisafunctionpointer*/
Thenitmaybeinvokedusingeitherofthesemethods:
fnptr(3); /*Method1ofinvokingthefunction*/
(*fnptr)(3); /*Method2ofinvokingthefunction*/
Theadvantageofthefirstmethodisanunclutteredsyntax.However,itmakesitlookasiffnptrisafunction,asopposedtobeingafunctionpointer.Someonemaintainingthecodemayendupsearchinginvainforthefunctionfnptr().Withmethod2,itismuchclearerthatwearedereferencingapointer.However,whenthedeclarationsgetcomplex,theadded(*)canbeasignificantburden.Throughouttheexamples,eachsyntaxisshown.Inpractice,thelattersyntaxseemstobemorepopular–andyoushoulduseonlyone.
4.Ineveryexample,thesyntaxforusingatypedefisalsogiven.Itisquitepermissibletouseatypedeftodefineacomplexdeclaration,andthenusethenewtypelikeasimpletype.Ifwestaywiththeexampleabove,thenanalternativedeclarationis:
typedefvoid(*PFV_I)(int);
/*DeclareaPVFV_Itypedvariableandinitit*/
PFV_Ifnptr=fna;
/*Callfnawithparameter3usingmethod1*/
fnptr(3);
/*Callfnawithparameter3usingmethod2*/
(*fnptr)(3);
ThetypedefdeclaresthetypePFV_Itobeapointertoafunctionthatreturnsvoidandispassedaninteger.Wethensimplydeclarefnptrtoavariableofthistype,anduseit.Typedefsareverygoodwhenyouregularlyuseacertainfunctionpointertype,sinceitsavesyouhavingtorememberandtypeinthedeclaration.Thedownsideofusingatypedef,isthefactthatitisnotobviousthatthevariablethathasbeendeclaredisapointertoafunction.Thus,justasforthetwoinvocationmethodsabove,youcangainsyntacticalsimplicitybyhidingtheunderlyingfunctionality.
Inthetypedefs,aconsistentnamingconventionisused.EverytypestartswithPF(PointertoFunction)andisthenfollowedwiththereturntype,followedbyanunderscore,thefirstparametertype,underscore,secondparametertypeandsoon.Forvoid,boolean,char,int,long,floatanddouble,thecharactersV,B,C,I,L,S,Dareused.(NotetheuseofS(ingle)forfloat,toavoidconfusionwithF(unction)).Forapointertoadatatype,thetypeisprecededwithP.ThusPLisapointertoalong.Ifaparameterisconst,thenacappearsintheappropriateplace.Thus,cPLisaconstpointertoalong,whereasaPcLisapointertoaconstlong,andcPcLisaconstpointertoaconstlong.Forvolatilequalifiers,visused.Forunsignedtypes,auprecedesthebasetype.Foruserdefineddatatypes,youareonyourown!
Anextremeexample:PFcPcI_uI_PvuC.ThisisapointertoafunctionthatreturnsaconstpointertoaconstIntegerthatispassedanunsignedintegerandapointertoavolatileunsignedchar.
Functionpointertemplates
Thefirstelevenexamplesaregenericinthesensethattheydonotusememoryspacequalifiersandhencemaybeusedonanytarget.Example12showshowtoaddmemoryspacequalifiers,suchthatallthecomponentsofthedeclarationendupinthecorrectmemoryspaces.
Example1
pf[]isastaticarrayofpointerstofunctionsthattakeanINTasanargumentandreturnvoid.
voidfna(INT); //Exampleprototypeofafunctiontobecalled
//Declarationusingtypedef
typedefvoid(*constPFV_I)(INT);
staticPFV_Ipf[]={fna,fnb,fnc,…fnz);
//Directdeclaration
staticvoid(*constpf[])(INT)={fna,fnb,fnc,…fnz};
//Exampleuse
INTa=6;
pf[jump_index](a); //Callingmethod1
(*pf[jump_index])(a); //Callingmethod2
Example2
pf[]isastaticarrayofpointerstofunctionsthattakeapointertoanINTasanargumentandreturnvoid.
voidfna(INT*); //Exampleprototypeofafunctiontobecalled
//Declarationusingtypedef
typedefvoid(*constPFV_PI)(INT*);
staticPVF_PI[]={fna,fnb,fnc,…fnz};
//Directdeclaration
staticvoid(*constpf[])(INT*)={fna,fnb,fnc,…fnz};
//Exampleuse
INTa=6;
pf[jump_index](&a); //Callingmethod1
(*pf[jump_index])(&a); //Callingmethod2
Example3
pf[]isastaticarrayofpointerstofunctionsthattakeanINTasanargumentandreturnaCHAR
CHARfna(INT); //Exampleprototypeofafunctiontobecalled
//Declarationusingtypedef
typedefCHAR(*constPFC_I)(INT);
staticPVC_I[]={fna,fnb,fnc,…fnz};
//Directdeclaration
staticCHAR(*constpf[])(INT)={fna,fnb,fnc,…fnz};
//Exampleuse
INTa=6;
CHARres;
res=pf[jump_index](a); //Callingmethod1
res=(*pf[jump_index])(a); //Callingmethod2
Example4
pf[]isastaticarrayofpointerstofunctionsthattakeanINTasanargumentandreturnapointertoaCHAR.
CHAR*fna(INT); //Exampleprototypeofafunctiontobecalled
//Declarationusingtypedef
typedefCHAR*(*constPFPC_I)(INT);
staticPVPC_I[]={fna,fnb,fnc,…fnz};
//Directdeclaration
staticCHAR*(*constpf[])(INT)={fna,fnb,fnc,…fnz};
//Exampleuse
INTa=6;
CHAR*res;
res=pf[jump_index](a); //Callingmethod1
res=(*pf[jump_index])(a); //Callingmethod2
Example5
pf[]isastaticarrayofpointerstofunctionsthattakeanINTasanargumentandreturnapointertoaconstCHAR(i.e.thepointermaybemodified,butwhatitpointstomaynot).
constCHAR*fna(INT); //Exampleprototypeofafunctiontobecalled
//Declarationusingtypedef
typedefconstCHAR*(*constPFPcC_I)(INT);
staticPVPcC_I[]={fna,fnb,fnc,…fnz};
//Directdeclaration
staticconstCHAR*(*constpf[])(INT)={fna,fnb,fnc,…fnz};
//Exampleuse
INTa=6;
constCHAR*res;
res=pf[jump_index](a); //Callingmethod2
res=(*pf[jump_index])(a); //Callingmethod2
Example6
pf[]isastaticarrayofpointerstofunctionsthattakeanINTasanargumentandreturnaconstpointertoaCHAR(i.e.thepointermaynotbemodified,butwhatitpointstomaybemodified).
CHAR*constfna(INTi);//Exampleprototypeofafunctiontobecalled
//Declarationusingtypedef
typedefCHAR*const(*constPFcPC_I)(INT);
staticPVcPC_I[]={fna,fnb,fnc,…fnz};
//Directdeclaration
staticCHAR*const(*constpf[])(INT)={fna,fnb,fnc,…fnz};
//Exampleuse
INTa=6;
CHAR*constres=pf[jump_index](a); //Callingmethod1
CHAR*constres=(*pf[jump_index])(a); //Callingmethod2
Example7
pf[]isastaticarrayofpointerstofunctionsthattakeanINTasanargumentandreturnaconstpointertoaconstCHAR(i.e.thepointer,norwhatitpointstomaybemodified)
constCHAR*constfna(INTi);//Examplefunctionprototype
//Declarationusingtypedef
typedefconstCHAR*const(*constPFcPcC_I)(INT);
staticPVcPcC_I[]={fna,fnb,fnc,…fnz};
//Directdeclaration
staticconstCHAR*const(*constpf[])(INT)={fna,fnb,fnc,…fnz};
//Exampleuse
INTa=6;
constCHAR*constres=pf[jump_index](a); //Callingmethod1
constCHAR*constres=(*pf[jump_index])(a); //Callingmethod2
Example8
pf[]isastaticarrayofpointerstofunctionsthattakeapointertoaconstINTasanargument(i.e.thepointermaybemodified,butwhatitpointstomaynot)andreturnaconstpointertoaconstCHAR(i.e.thepointer,norwhatitpointstomaybemodified)
constCHAR*constfna(constINT*i); //Exampleprototype
//Declarationusingtypedef
typedefconstCHAR*const(*constPFcPcC_PcI)(constINT*);
staticPVcPcC_PcI[]={fna,fnb,fnc,…fnz};
//Directdeclaration
staticconstCHAR*const(*constpf[])(constINT*)={fna,fnb,fnc,…fnz};
//Exampleuse
constINTa=6;
constINT*aptr;
aptr=&a;
constCHAR*constres=pf[jump_index](aptr); //Callingmethod1
constCHAR*constres=(*pf[jump_index])(aptr);//Callingmethod2
Example9
pf[]isastaticarrayofpointerstofunctionsthattakeaconstpointertoanINTasanargument(i.e.thepointermaynotbemodified,butwhatitpointstomay)andreturnaconstpointertoaconstCHAR(i.e.thepointer,norwhatitpointstomaybemodified)
constCHAR*constfna(INT*consti); //Exampleprototype
//Declarationusingtypedef
typedefconstCHAR*const(*constPFcPcC_cPI)(INT*const);
staticPVcPcC_cPI[]={fna,fnb,fnc,…fnz};
//Directdeclaration
staticconstCHAR*const(*constpf[])(INT*const)={fna,fnb,fnc,…fnz};
//Exampleuse
INTa=6;
INT*constaptr=&a;
constCHAR*constres=pf[jump_index](aptr); //Method1
constCHAR*constres=(*pf[jump_index])(aptr); //Method2
Example10
pf[]isastaticarrayofpointerstofunctionsthattakeaconstpointertoaconstINTasanargument(i.e.thepointernorwhatitpointstomaybemodified)andreturnaconstpointertoaconstCHAR(i.e.thepointer,norwhatitpointstomaybemodified)
constCHAR*constfna(constINT*consti); //Exampleprototype
//Declarationusingtypedef
typedefconstCHAR*const(*constPFcPcC_cPcI)(constINT*const);
staticPVcPcC_cPcI[]={fna,fnb,fnc,…fnz};
//Directdeclaration
staticconstCHAR*const(*constpf[])(constINT*const)={fna,fnb,fnc,…fnz};
//Exampleuse
constINTa=6;
constINT*constaptr=&a;
constCHAR*constres=pf[jump_index](aptr); //Method1
constCHAR*constres=(*pf[jump_index])(aptr); //Method2
Thisexamplemanagestocombinefiveincidencesofconstandoneofstaticintoasingledeclaration.Forallofitscomplexity,however,thisisnotanartificialexample.Youcouldgoaheadandremovealltheconstandstaticdeclarationsandthecodewouldstillwork.Itwould,however,bealotlesssafe,andpotentiallylessefficient.
Justtobreakupthemonotony,hereisthesamedeclaration,butwithatwist.
Example11
pf[]isastaticarrayofpointerstofunctionsthattakeaconstpointertoaconstINTasanargument(i.e.thepointernorwhatitpointstomaybemodified)andreturnaconstpointertoavolatileCHAR(i.e.thepointermaynotbemodified,butwhatitpointstomaychangeunexpectedly)
volatileCHAR*constfna(constINT*consti); //Exampleprototype
//Declarationusingtypedef
typedefvolatileCHAR*const(*constPFcPvC_cPcI)(constINT*const);
staticPVcPvC_cPcI[]={fna,fnb,fnc,…fnz};
//Directdeclaration
staticvolatileCHAR*const(*constpf[])(constINT*const)={fna,fnb,fnc,…fnz};
//Exampleuse
constINTa=6;
constINT*constaptr=&a;
volatileCHAR*constres=pf[jump_index](aptr); //Method1
volatileCHAR*constres=(*pf[jump_index])(aptr); //Method2
while(*res)
; //Waitforvolatileregistertoclear
Withmemoryspacequalifiers,thingscangetevenmorehairy.Formostvendors,thememoryspacequalifieristreatedsyntacticallyasatypequalifier(suchasconstorvolatile)andthusfollowsthesameplacementrules.Forconsistency,Iplacetypequalifierstotheleftofthe“thing”beingqualified.Wheretherearemultipletypequalifiers,alphabeticorderingisused.Sincememoryspacequalifiersaretypicallycompilerextensions,theyarenormallyprecededbyanunderscore,andhencecomefirstalphabetically.Thus,anastydeclarationmaylooklikethis:
_ramconstvolatileUCHARstatus_register;
Todemonstratememoryspacequalifieruse,hereisexample11again,exceptthistimememoryspacequalifiershavebeenadded.Thequalifiersarenamed_m1…_m5.
Example12
pf[]isastaticarrayofpointerstofunctionsthattakeaconstpointertoaconstINTasanargument(i.e.thepointernorwhatitpointstomaybemodified)andreturnaconstpointertoavolatileCHAR(i.e.thepointermaybemodified,butwhatitpointstomaychangeunexpectedly).Eachelementofthedeclarationliesinadifferentmemoryspace.Inthisparticularcase,itisassumedthatyoucanevendeclarethememoryspaceinwhichparameterspassedbyvalueappear.Thisisextreme,butisjustifiedonpedagogicalgrounds.
/*Anexampleprototype.Thisdeclarationreadsasfollows.
*Functionfnaispassedaconstpointerin_m5spacethatpointstoa
*constintegerin_m4space.Itreturnsaconstpointerin_m2spaceto
*avolatilecharacterin_m1space.
*/
_m1volatileCHAR*_m2constfna(_m4constINT*_m5consti);
/*Declarationusingtypedef.Thisdeclarationreadsasfollows.
*PFcPvC_cPcIisapointertofunctiondatatype,variablesbased
*uponwhichliein_m3space.EachFunctionispassedaconst
*pointerin_m5spacethatpointstoaconstintegerin_m4space.
*Itreturnsaconstpointerin_m2spacetoavolatilecharacter
*in_m1space.
*/
typedef_m1volatileCHAR*_m2const(*_m3constPFcPvC_cPcI)(_m4constINT*_m5const);
staticPVcPvC_cPcI[]={fna,fnb,fnc,…fnz};
/*Directdeclaration.Thisdeclarationreadsasfollows.pf[]is
*astaticallyallocatedconstantarrayin_m3spaceofpointerstofunctions.
*EachFunctionispassedaconstpointerin_m5spacethatpointsto
*aconstintegerin_m4space.Itreturnsaconstpointerin_m2space
*toavolatilecharacterin_m1space.
*/
static_m1volatileCHAR*_m2const(*_m3constpf[])(_m4constINT*_m5const)={fna,fnb,fnc,…fnz};
//Declareaconstvariablethatliesin_m4space
_m4constINTa=6;
//Nowdeclareaconstpointerin_m5spacethatpointstoaconst
//variablethatisin_m4space
_m4constINT*_m5constaptr=&a;
//Makethefunctioncall,andgetbackthepointer
volatileCHAR*constres=pf[jump_index](&a); //Method1
volatileCHAR*constres=(*pf[jump_index])(&a); //Method2
while(*res)
; //Waitforvolatileregistertoclear
Acknowledgments
MythankstoMikeStevensnotonlyforreadingoverthismanuscriptandmakingsomeexcellentsuggestionsbutalsoforovertheyearsshowingmemorewaystousefunctionpointersthatIeverdreamedwaspossible.
ThisarticlewaspublishedintheMay1999issueofEmbeddedSystemsProgramming.Ifyouwishtocitethearticleinyourownwork,youmayfindthefollowingMLA-styleinformationhelpful:
Jones,Nigel.“ArraysofPointerstoFunctions”EmbeddedSystemsProgramming,May1999.
Thisentrywasposted
onThursday,December17th,2009at4:43pm andisfiledunderPublications.
YoucanfollowanyresponsestothisentrythroughtheRSS2.0feed.
Bothcommentsandpingsarecurrentlyclosed.
Commentsareclosed.
StackOverflow
NigelJones
NigelJonesisanembeddedsystemsconsultantwithover20yearsofexperiencedesigningelectroniccircuitsandfirmware.(fullbio)
Pages
ContactNigel
Links
ArticlesonEmbeddedSystems
EmbeddedCCodingStandard
EmbeddedSoftwareTraininginaBox
EmbeddedSystemsDesign,Consulting,andExpertWitnessServices
RecentPosts
EEPROMWearLeveling
Hammingdistances
Peakdetectionofatimeseries
BoeingDreamliner‘Bug’
Freescalecustomerservice
Firmalware
ShiftingStyles
Theengineering–marketingdivide
Replacingnestedswitcheswithmulti-dimensionalarraysofpointerstofunctions
Idlingalong,(orwhattodointheidletask)
RecentCommentsNigelJonesonEfficientCTips#5–Make‘local’functions‘static’jimonEfficientCTips#5–Make‘local’functions‘static’YuriGribovonEfficientCTips#5–Make‘local’functions‘static’Mico/Milang,abasiccompiler–MinaPêcheuxonEfficientCTip#12–BewaryofswitchstatementsjohnonIsMISRAcomplianceworthwhile?Categories
Algorithms(16)
CodingStandards(23)
Compilers/Tools(25)
Consulting(14)
EffectiveC/C++(13)
EfficientC/C++(20)
FirmwareBugs(12)
GeneralCissues(49)
Hardware(22)
LowPowerDesign(7)
Minimizingmemoryconsumption(3)
Publications(12)
RTOSMultithreading(2)
Uncategorized(32)
Archives
July2017 (1)
June2017 (1)
September2015 (1)
May2015 (1)
March2015 (1)
February2015 (1)
November2014 (1)
April2014 (1)
March2014 (1)
April2013 (1)
February2013 (1)
January2013 (1)
December2012 (1)
July2012 (2)
June2012 (2)
March2012 (1)
February2012 (2)
December2011 (2)
September2011 (2)
August2011 (1)
June2011 (1)
May2011 (1)
March2011 (1)
February2011 (4)
January2011 (1)
December2010 (2)
November2010 (3)
October2010 (2)
September2010 (2)
August2010 (8)
June2010 (2)
May2010 (2)
April2010 (1)
March2010 (3)
February2010 (4)
January2010 (2)
December2009 (18)
November2009 (3)
October2009 (7)
September2009 (8)
August2009 (4)
July2009 (4)
June2009 (4)
May2009 (4)
April2009 (5)
March2009 (5)
February2009 (6)
January2009 (4)
December2008 (3)
November2008 (3)
October2008 (1)
September2008 (2)
August2008 (3)
July2008 (1)
June2008 (3)
May2008 (2)
April2008 (1)
February2008 (1)
January2008 (3)
August2007 (2)
July2007 (1)
June2007 (2)
May2007 (2)
April2007 (1)
March2007 (1)
December2006 (3)
November2006 (2)
October2006 (2)
September2006 (5)
TagsAVR
Bitfields
bootstraploading
CodingStandards
Compilers
corrosion
CPUselection
CTest
developmentcosts
EEPROM
ethics
flags
FRAM
GCC
holdingcurrent
I2C
IAR
Independentcontractor
Keil
LED
Lint
Lookuptable
LUT
Medianfilter
memory
memoryconsumption
Microchip
MISRA
MSP430
optimization
parameterpassing
PC-Lint
PIC
printf
prototypes
PWM
Relays
Rowley
signed
taxcode
unsigned
variablenaming
volatile
voltagegradient
Windows
EmbeddedGurus-ExpertsonEmbeddedSoftware
websitebyAccentInteractive