How do function pointers in C work? - Stack Overflow

文章推薦指數: 80 %
投票人數:10人

A function pointer is a variable that contains the address of a function. Since it is a pointer variable though with ... Resultsfromthe2022DeveloperSurveyarenowavailable Home Public Questions Tags Users Companies Collectives ExploreCollectives Teams StackOverflowforTeams –Startcollaboratingandsharingorganizationalknowledge. CreateafreeTeam WhyTeams? Teams CreatefreeTeam Collectives™onStackOverflow Findcentralized,trustedcontentandcollaboratearoundthetechnologiesyouusemost. Learnmore Teams Q&Aforwork Connectandshareknowledgewithinasinglelocationthatisstructuredandeasytosearch. Learnmore HowdofunctionpointersinCwork? AskQuestion Asked 13years,1monthago Modified 1year,5monthsago Viewed 921ktimes 1421 1075 IhadsomeexperiencelatelywithfunctionpointersinC. Sogoingonwiththetraditionofansweringyourownquestions,Idecidedtomakeasmallsummaryoftheverybasics,forthosewhoneedaquickdive-intothesubject. cfunction-pointers Share Improvethisquestion Follow askedMay8,2009at15:49 communitywiki YuvalAdam 3 40 Also:Forabitofanin-depthanalysisofCpointers,seeblogs.oracle.com/ksplice/entry/the_ksplice_pointer_challenge.Also,ProgrammingfromtheGroundUpshowshowtheyworkonthemachinelevel.UnderstandingC's"memorymodel"isveryusefulforunderstandinghowCpointerswork. – Abbafei May22,2013at11:17 9 Greatinfo.Bythetitlethough,Iwouldhaveexpectedtoreallyseeanexplanationofhow"functionpointerswork",nothowtheyarecoded:) – BogdanAlexandru Aug28,2014at12:39 1 Thefollowinganswerisshorterandalotmucheasiertounderstand:stackoverflow.com/a/142809/2188550 – user2188550 Jan8,2021at22:31 Addacomment  |  11Answers 11 Sortedby: Resettodefault Highestscore(default) Trending(recentvotescountmore) Datemodified(newestfirst) Datecreated(oldestfirst) 1655 FunctionpointersinC Let'sstartwithabasicfunctionwhichwewillbepointingto: intaddInt(intn,intm){ returnn+m; } Firstthing,let'sdefineapointertoafunctionwhichreceives2intsandreturnsanint: int(*functionPtr)(int,int); Nowwecansafelypointtoourfunction: functionPtr=&addInt; Nowthatwehaveapointertothefunction,let'suseit: intsum=(*functionPtr)(2,3);//sum==5 Passingthepointertoanotherfunctionisbasicallythesame: intadd2to3(int(*functionPtr)(int,int)){ return(*functionPtr)(2,3); } Wecanusefunctionpointersinreturnvaluesaswell(trytokeepup,itgetsmessy): //thisisafunctioncalledfunctionFactorywhichreceivesparametern //andreturnsapointertoanotherfunctionwhichreceivestwoints //anditreturnsanotherint int(*functionFactory(intn))(int,int){ printf("Gotparameter%d",n); int(*functionPtr)(int,int)=&addInt; returnfunctionPtr; } Butit'smuchnicertouseatypedef: typedefint(*myFuncDef)(int,int); //notethatthetypedefnameisindeedmyFuncDef myFuncDeffunctionFactory(intn){ printf("Gotparameter%d",n); myFuncDeffunctionPtr=&addInt; returnfunctionPtr; } Share Improvethisanswer Follow editedDec29,2016at22:23 TomZych 12.9k99goldbadges3535silverbadges5252bronzebadges answeredMay8,2009at15:49 YuvalAdamYuvalAdam 156k9090goldbadges298298silverbadges388388bronzebadges 11 24 Thanksforthegreatinfo.Couldyouaddsomeinsightonwherefunctionpointersareusedorhappentobeparticularlyuseful? – Rich.Carpenter May8,2009at15:55 361 "functionPtr=&addInt;"canalsobewritten(andoftenis)as"functionPtr=addInt;"whichisalsovalidsincethestandardsaysthatafunctionnameinthiscontextisconvertedtotheaddressofthefunction. – hlovdal May9,2009at14:39 25 hlovdal,inthiscontextit'sinterestingtoexplainthatthisiswhatenablesonetowritefunctionPtr=******************addInt; – JohannesSchaub-litb May10,2009at17:54 117 @Rich.CarpenterIknowthisis4yearstoolate,butIfigureotherpeoplemightbenefitfromthis:Functionpointersareusefulforpassingfunctionsasparameterstootherfunctions.Ittookalotofsearchingformetofindthatanswerforsomeoddreason.Sobasically,itgivesCpseudofirst-classfunctionality. – giant91 Oct13,2013at2:28 27 @Rich.Carpenter:functionpointersareniceforruntimeCPUdetection.HavemultipleversionsofsomefunctionstotakeadvantageofSSE,popcnt,AVX,etc.Atstartup,setyourfunctionpointerstothebestversionofeachfunctionforthecurrentCPU.Inyourothercode,justcallthroughthefunctionpointerinsteadofhavingconditionalbranchesontheCPUfeatureseverywhere.Thenyoucandocomplicatedlogicaboutdecidingthatwell,eventhoughthisCPUsupportspshufb,it'sslow,sotheearlierimplementationisstillfaster.x264/x265usethisextensively,andareopensource. – PeterCordes Aug30,2015at2:22  |  Show6morecomments 328 FunctionpointersinCcanbeusedtoperformobject-orientedprogramminginC. Forexample,thefollowinglinesiswritteninC: Strings1=newString(); s1->set(s1,"hello"); Yes,the->andthelackofanewoperatorisadeadgiveaway,butitsureseemstoimplythatwe'resettingthetextofsomeStringclasstobe"hello". Byusingfunctionpointers,itispossibletoemulatemethodsinC. Howisthisaccomplished? TheStringclassisactuallyastructwithabunchoffunctionpointerswhichactasawaytosimulatemethods.ThefollowingisapartialdeclarationoftheStringclass: typedefstructString_Struct*String; structString_Struct { char*(*get)(constvoid*self); void(*set)(constvoid*self,char*value); int(*length)(constvoid*self); }; char*getString(constvoid*self); voidsetString(constvoid*self,char*value); intlengthString(constvoid*self); StringnewString(); Ascanbeseen,themethodsoftheStringclassareactuallyfunctionpointerstothedeclaredfunction.InpreparingtheinstanceoftheString,thenewStringfunctioniscalledinordertosetupthefunctionpointerstotheirrespectivefunctions: StringnewString() { Stringself=(String)malloc(sizeof(structString_Struct)); self->get=&getString; self->set=&setString; self->length=&lengthString; self->set(self,""); returnself; } Forexample,thegetStringfunctionthatiscalledbyinvokingthegetmethodisdefinedasthefollowing: char*getString(constvoid*self_obj) { return((String)self_obj)->internal->value; } Onethingthatcanbenoticedisthatthereisnoconceptofaninstanceofanobjectandhavingmethodsthatareactuallyapartofanobject,soa"selfobject"mustbepassedinoneachinvocation.(Andtheinternalisjustahiddenstructwhichwasomittedfromthecodelistingearlier--itisawayofperforminginformationhiding,butthatisnotrelevanttofunctionpointers.) So,ratherthanbeingabletodos1->set("hello");,onemustpassintheobjecttoperformtheactionons1->set(s1,"hello"). Withthatminorexplanationhavingtopassinareferencetoyourselfoutoftheway,we'llmovetothenextpart,whichisinheritanceinC. Let'ssaywewanttomakeasubclassofString,sayanImmutableString.Inordertomakethestringimmutable,thesetmethodwillnotbeaccessible,whilemaintainingaccesstogetandlength,andforcethe"constructor"toacceptachar*: typedefstructImmutableString_Struct*ImmutableString; structImmutableString_Struct { Stringbase; char*(*get)(constvoid*self); int(*length)(constvoid*self); }; ImmutableStringnewImmutableString(constchar*value); Basically,forallsubclasses,theavailablemethodsareonceagainfunctionpointers.Thistime,thedeclarationforthesetmethodisnotpresent,therefore,itcannotbecalledinaImmutableString. AsfortheimplementationoftheImmutableString,theonlyrelevantcodeisthe"constructor"function,thenewImmutableString: ImmutableStringnewImmutableString(constchar*value) { ImmutableStringself=(ImmutableString)malloc(sizeof(structImmutableString_Struct)); self->base=newString(); self->get=self->base->get; self->length=self->base->length; self->base->set(self->base,(char*)value); returnself; } IninstantiatingtheImmutableString,thefunctionpointerstothegetandlengthmethodsactuallyrefertotheString.getandString.lengthmethod,bygoingthroughthebasevariablewhichisaninternallystoredStringobject. Theuseofafunctionpointercanachieveinheritanceofamethodfromasuperclass. WecanfurthercontinuetopolymorphisminC. Ifforexamplewewantedtochangethebehaviorofthelengthmethodtoreturn0allthetimeintheImmutableStringclassforsomereason,allthatwouldhavetobedoneisto: Addafunctionthatisgoingtoserveastheoverridinglengthmethod. Gotothe"constructor"andsetthefunctionpointertotheoverridinglengthmethod. AddinganoverridinglengthmethodinImmutableStringmaybeperformedbyaddinganlengthOverrideMethod: intlengthOverrideMethod(constvoid*self) { return0; } Then,thefunctionpointerforthelengthmethodintheconstructorishookeduptothelengthOverrideMethod: ImmutableStringnewImmutableString(constchar*value) { ImmutableStringself=(ImmutableString)malloc(sizeof(structImmutableString_Struct)); self->base=newString(); self->get=self->base->get; self->length=&lengthOverrideMethod; self->base->set(self->base,(char*)value); returnself; } Now,ratherthanhavinganidenticalbehaviorforthelengthmethodinImmutableStringclassastheStringclass,nowthelengthmethodwillrefertothebehaviordefinedinthelengthOverrideMethodfunction. ImustaddadisclaimerthatIamstilllearninghowtowritewithanobject-orientedprogrammingstyleinC,sothereprobablyarepointsthatIdidn'texplainwell,ormayjustbeoffmarkintermsofhowbesttoimplementOOPinC.Butmypurposewastotrytoillustrateoneofmanyusesoffunctionpointers. Formoreinformationonhowtoperformobject-orientedprogramminginC,pleaserefertothefollowingquestions: Object-OrientationinC? CanyouwriteobjectorientedcodeinC? Share Improvethisanswer Follow editedMay23,2017at12:18 communitywiki 3revs,2users99%coobird 11 29 Thisanswerishorrible!NotonlyitimpliesthatOOsomehowdependsondotnotation,italsoencouragesputtingjunkintoyourobjects! – AlexeiAverchenko Sep16,2012at14:30 33 ThisisOOallright,butnotanywhereneartheC-styleOO.WhatyouhavebrokenlyimplementedisJavascript-styleprototype-basedOO.TogetC++/Pascal-styleOO,you'dneedto:1.Haveaconststructforavirtualtableofeachclasswithvirtualmembers.2.Havepointertothatstructinpolymorphicobjects.3.Callvirtualmethodsviathevirtualtable,andallothermethodsdirectly--usuallybystickingtosomeClassName_methodNamefunctionnamingconvention.OnlythenyougetthesameruntimeandstoragecostsasyoudoinC++andPascal. – Kubahasn'tforgottenMonica Mar18,2013at21:53 20 WorkingOOwithalanguagethatisnotintendedtobeOOisalwaysabadidea.IfyouwantOOandstillhaveCjustworkwithC++. – rbaleksandar Jul4,2013at15:21 27 @rbaleksandarTellthattotheLinuxkerneldevelopers."alwaysabadidea"isstrictlyyouropinion,withwhichIfirmlydisagree. – JonathonReinhart Apr30,2015at12:31 7 Ilikethisanswerbutdon'tcastmalloc – cat Sep29,2016at14:41  |  Show6morecomments 254 Theguidetogettingfired:HowtoabusefunctionpointersinGCConx86machinesbycompilingyourcodebyhand: Thesestringliteralsarebytesof32-bitx86machinecode.0xC3isanx86retinstruction. Youwouldn'tnormallywritethesebyhand,you'dwriteinassemblylanguageandthenuseanassemblerlikenasmtoassembleitintoaflatbinarywhichyouhexdumpintoaCstringliteral. ReturnsthecurrentvalueontheEAXregister inteax=((int(*)())("\xc31000 Youcanevenwritearecursivefunctionthatcountsto100 constchar*lol="\x8b\x5c\x24\x4\x3d\xe8\x3\x0\x0\x7e\x2\x31\xc0\x83\xf8\x64\x7d\x6\x40\x53\xff\xd3\x5b\xc3\xc3: 0:8b442404moveax,DWORDPTR[esp+0x4]#loadint*aargfromthestack 4:8b5c2408movebx,DWORDPTR[esp+0x8]#ebx=b 8:8b00moveax,DWORDPTR[eax]#dereference:eax=*a a:8b1bmovebx,DWORDPTR[ebx] c:31c3xorebx,eax#pointlessxor-swap e:31d8xoreax,ebx#insteadofjuststoringwithoppositeregisters 10:31c3xorebx,eax 12:8b4c2404movecx,DWORDPTR[esp+0x4]#reloadafromthestack 16:8901movDWORDPTR[ecx],eax#storeto*a 18:8b4c2408movecx,DWORDPTR[esp+0x8] 1c:8919movDWORDPTR[ecx],ebx 1e:c3ret notshown:thelaterbytesareASCIItextdocumentation they'renotexecutedbytheCPUbecausetheretinstructionsendsexecutionbacktothecaller Thismachinecodewill(probably)workin32-bitcodeonWindows,Linux,OSX,andsoon:thedefaultcallingconventionsonallthoseOSespassargsonthestackinsteadofmoreefficientlyinregisters.ButEBXiscall-preservedinallthenormalcallingconventions,sousingitasascratchregisterwithoutsaving/restoringitcaneasilymakethecallercrash. Share Improvethisanswer Follow editedOct9,2018at13:58 communitywiki 4revs,3users50%Lee 19 9 Note:thisdoesn'tworkifDataExecutionPreventionisenabled(e.g.onWindowsXPSP2+),becauseCstringsarenotnormallymarkedasexecutable. – SecurityMatt Feb12,2013at5:53 5 HiMatt!Dependingontheoptimizationlevel,GCCwillofteninlinestringconstantsintotheTEXTsegment,sothiswillworkevenonnewerversionofwindowsprovidedthatyoudon'tdisallowthistypeofoptimization.(IIRC,theMINGWversionatthetimeofmypostovertwoyearsagoinlinesstringliteralsatthedefaultoptimizationlevel) – Lee Jan2,2014at6:20 11 couldsomeonepleaseexplainwhat'shappeninghere?Whatarethoseweirdlookingstringliterals? – ajay Jan20,2014at10:17 62 @ajayItlookslikehe'swritingrawhexidecimalvalues(forinstance'\x00'isthesameas'/0',they'rebothequalto0)intoastring,thencastingthestringintoaCfunctionpointer,thenexecutingtheCfunctionpointerbecausehe'sthedevil. – ejk314 Feb21,2014at21:27 4 hiFUZxxl,Ithinkitmightvarybasedonthecompilerandtheoperatingsystemversion.Theabovecodeseemstorunfineoncodepad.org;codepad.org/FMSDQ3ME – Lee Mar13,2014at0:48  |  Show14morecomments 121 Oneofmyfavoriteusesforfunctionpointersisascheapandeasyiterators- #include #defineMAX_COLORS256 typedefstruct{ char*name; intred; intgreen; intblue; }Color; ColorColors[MAX_COLORS]; voideachColor(void(*fp)(Color*c)){ inti; for(i=0;iname) printf("%s=%i,%i,%i\n",c->name,c->red,c->green,c->blue); } intmain(){ Colors[0].name="red"; Colors[0].red=255; Colors[1].name="blue"; Colors[1].blue=255; Colors[2].name="black"; eachColor(printColor); } Share Improvethisanswer Follow editedJul24,2012at16:40 communitywiki 2revs,2users99%Nick 2 9 Youshouldalsopassapointertouser-specifieddataifyouwanttosomehowextractanyoutputfromiterations(thinkclosures). – AlexeiAverchenko Sep16,2012at14:32 3 Agreed.Allofmyiteratorslooklikethis:int(*cb)(void*arg,...).Thereturnvalueoftheiteratoralsoletsmestopearly(ifnonzero). – JonathonReinhart Apr30,2015at12:35 Addacomment  |  25 Functionpointersbecomeeasytodeclareonceyouhavethebasicdeclarators: id:ID:IDisa Pointer:*D:Dpointerto Function:D():Dfunctiontakingreturning WhileDisanotherdeclaratorbuiltusingthosesamerules.Intheend,somewhere,itendswithID(seebelowforanexample),whichisthenameofthedeclaredentity.Let'strytobuildafunctiontakingapointertoafunctiontakingnothingandreturningint,andreturningapointertoafunctiontakingacharandreturningint.Withtype-defsit'slikethis typedefintReturnFunction(char); typedefintParameterFunction(void); ReturnFunction*f(ParameterFunction*p); Asyousee,it'sprettyeasytobuilditupusingtypedefs.Withouttypedefs,it'snothardeitherwiththeabovedeclaratorrules,appliedconsistently.Asyouseeimissedoutthepartthepointerpointsto,andthethingthefunctionreturns.That'swhatappearsattheveryleftofthedeclaration,andisnotofinterest:It'saddedattheendifonebuiltupthedeclaratoralready.Let'sdothat.Buildingitupconsistently,firstwordy-showingthestructureusing[and]: functiontaking [pointerto[functiontaking[void]returning[int]]] returning [pointerto[functiontaking[char]returning[int]]] Asyousee,onecandescribeatypecompletelybyappendingdeclaratorsoneaftereachother.Constructioncanbedoneintwoways.Oneisbottom-up,startingwiththeveryrightthing(leaves)andworkingthewaythroughuptotheidentifier.Theotherwayistop-down,startingattheidentifier,workingthewaydowntotheleaves.I'llshowbothways. BottomUp Constructionstartswiththethingattheright:Thethingreturned,whichisthefunctiontakingchar.Tokeepthedeclaratorsdistinct,i'mgoingtonumberthem: D1(char); Insertedthecharparameterdirectly,sinceit'strivial.AddingapointertodeclaratorbyreplacingD1by*D2.Notethatwehavetowrapparenthesesaround*D2.Thatcanbeknownbylookinguptheprecedenceofthe*-operatorandthefunction-calloperator().Withoutourparentheses,thecompilerwouldreaditas*(D2(charp)).ButthatwouldnotbeaplainreplaceofD1by*D2anymore,ofcourse.Parenthesesarealwaysallowedarounddeclarators.Soyoudon'tmakeanythingwrongifyouaddtoomuchofthem,actually. (*D2)(char); Returntypeiscomplete!Now,let'sreplaceD2bythefunctiondeclaratorfunctiontakingreturning,whichisD3()whichweareatnow. (*D3())(char) Notethatnoparenthesesareneeded,sincewewantD3tobeafunction-declaratorandnotapointerdeclaratorthistime.Great,onlythingleftistheparametersforit.Theparameterisdoneexactlythesameaswe'vedonethereturntype,justwithcharreplacedbyvoid.Soi'llcopyit: (*D3((*ID1)(void)))(char) I'vereplacedD2byID1,sincewearefinishedwiththatparameter(it'salreadyapointertoafunction-noneedforanotherdeclarator).ID1willbethenameoftheparameter.Now,itoldaboveattheendoneaddsthetypewhichallthosedeclaratormodify-theoneappearingattheveryleftofeverydeclaration.Forfunctions,thatbecomesthereturntype.Forpointersthepointedtotypeetc...It'sinterestingwhenwrittendownthetype,itwillappearintheoppositeorder,attheveryright:)Anyway,substitutingityieldsthecompletedeclaration.Bothtimesintofcourse. int(*ID0(int(*ID1)(void)))(char) I'vecalledtheidentifierofthefunctionID0inthatexample. TopDown Thisstartsattheidentifierattheveryleftinthedescriptionofthetype,wrappingthatdeclaratoraswewalkourwaythroughtheright.Startwithfunctiontakingreturning ID0() Thenextthinginthedescription(after"returning")waspointerto.Let'sincorporateit: *ID0() Thenthenextthingwasfunctontakingreturning.Theparameterisasimplechar,soweputitinrightawayagain,sinceit'sreallytrivial. (*ID0())(char) Notetheparenthesesweadded,sinceweagainwantthatthe*bindsfirst,andthenthe(char).Otherwiseitwouldreadfunctiontakingreturningfunction....Noes,functionsreturningfunctionsaren'tevenallowed. Nowwejustneedtoput.Iwillshowashortversionofthederiveration,sinceithinkyoualreadybynowhavetheideahowtodoit. pointerto:*ID1 ...functiontakingvoidreturning:(*ID1)(void) Justputintbeforethedeclaratorslikewedidwithbottom-up,andwearefinished int(*ID0(int(*ID1)(void)))(char) Thenicething Isbottom-uportop-downbetter?I'musedtobottom-up,butsomepeoplemaybemorecomfortablewithtop-down.It'samatteroftasteithink.Incidentally,ifyouapplyalltheoperatorsinthatdeclaration,youwillendupgettinganint: intv=(*ID0(some_function_pointer))(some_char); ThatisanicepropertyofdeclarationsinC:Thedeclarationassertsthatifthoseoperatorsareusedinanexpressionusingtheidentifier,thenityieldsthetypeontheveryleft.It'slikethatforarraystoo. Hopeyoulikedthislittletutorial!Nowwecanlinktothiswhenpeoplewonderaboutthestrangedeclarationsyntaxoffunctions.ItriedtoputaslittleCinternalsaspossible.Feelfreetoedit/fixthingsinit. Share Improvethisanswer Follow editedMay9,2009at13:38 communitywiki 3revsJohannesSchaub-litb Addacomment  |  24 Anothergooduseforfunctionpointers:Switchingbetweenversionspainlessly They'reveryhandytouseforwhenyouwantdifferentfunctionsatdifferenttimes,ordifferentphasesofdevelopment.Forinstance,I'mdevelopinganapplicationonahostcomputerthathasaconsole,butthefinalreleaseofthesoftwarewillbeputonanAvnetZedBoard(whichhasportsfordisplaysandconsoles,buttheyarenotneeded/wantedforthefinalrelease).Soduringdevelopment,Iwilluseprintftoviewstatusanderrormessages,butwhenI'mdone,Idon'twantanythingprinted.Here'swhatI'vedone: version.h //First,undefineallmacrosassociatedwithversion.h #undefDEBUG_VERSION #undefRELEASE_VERSION #undefINVALID_VERSION //Definewhichversionwewanttouse #defineDEBUG_VERSION//Thecurrentversion //#defineRELEASE_VERSION//Tobeuncommentedwhenfinisheddebugging #ifndef__VERSION_H_/*preventcircularinclusions*/ #define__VERSION_H_/*byusingprotectionmacros*/ voidboard_init(); voidnoprintf(constchar*c,...);//mimictheprintfprototype #endif //Mimicstheprintffunctionprototype.ThisiswhatI'llactually //usetoprintstufftothescreen void(*zprintf)(constchar*,...); //Ifdebugversion,useprintf #ifdefDEBUG_VERSION #include #endif //Ifbothdebugandreleaseversion,error #ifdefDEBUG_VERSION #ifdefRELEASE_VERSION #defineINVALID_VERSION #endif #endif //Ifneitherdebugorreleaseversion,error #ifndefDEBUG_VERSION #ifndefRELEASE_VERSION #defineINVALID_VERSION #endif #endif #ifdefINVALID_VERSION //Won'tallowcompilationwithoutavalidversiondefine #error"Invalidversiondefinition" #endif Inversion.cIwilldefinethe2functionprototypespresentinversion.h version.c #include"version.h" /*****************************************************************************/ /** *@nameboard_init * *Setsuptheapplicationbasedontheversiontypedefinedinversion.h. *IncludesallowingorprohibitingprintingtoSTDOUT. * *MUSTBECALLEDFIRSTTHINGINMAIN * *@returnNone * *****************************************************************************/ voidboard_init() { //Assigntheprintfunctiontothecorrectfunctionpointer #ifdefDEBUG_VERSION zprintf=&printf; #else //Definedbelowthisfunction zprintf=&noprintf; #endif } /*****************************************************************************/ /** *@namenoprintf * *simplyreturnswithnoactionsperformed * *@returnNone * *****************************************************************************/ voidnoprintf(constchar*c,...) { return; } Noticehowthefunctionpointerisprototypedinversion.hasvoid(*zprintf)(constchar*,...);Whenitisreferencedintheapplication,itwillstartexecutingwhereveritispointing,whichhasyettobedefined. Inversion.c,noticeintheboard_init()functionwherezprintfisassignedauniquefunction(whosefunctionsignaturematches)dependingontheversionthatisdefinedinversion.hzprintf=&printf;zprintfcallsprintffordebuggingpurposesorzprintf=&noprint;zprintfjustreturnsandwillnotrununnecessarycode Runningthecodewilllooklikethis: mainProg.c #include"version.h" #include intmain() { //Mustrunboard_init(),whichassignsthefunction //pointertoanactualfunction board_init(); void*ptr=malloc(100);//Allocate100bytesofmemory //mallocreturnsNULLifunabletoallocatethememory. if(ptr==NULL) { zprintf("Unabletoallocatememory\n"); return1; } //Otherthingstodo... return0; } Theabovecodewilluseprintfifindebugmode,ordonothingifinreleasemode.Thisismucheasierthangoingthroughtheentireprojectandcommentingoutordeletingcode.AllthatIneedtodoischangetheversioninversion.handthecodewilldotherest! Share Improvethisanswer Follow editedJun11,2013at15:36 communitywiki 2revsZackSheffield 1 6 Ustandtolosealotofperformancetime.InsteadyoucoulduseamacrothatenablesanddisablesasectionofcodebasedonDebug/Release. – AlphaGoku May11,2018at13:41 Addacomment  |  20 Functionpointerisusuallydefinedbytypedef,andusedasparam&returnvalue. Aboveanswersalreadyexplainedalot,Ijustgiveafullexample: #include #defineNUM_A1 #defineNUM_B2 //defineafunctionpointertype typedefint(*two_num_operation)(int,int); //anactualstandalonefunction staticintsum(inta,intb){ returna+b; } //usefunctionpointerasparam, staticintsum_via_pointer(inta,intb,two_num_operationfunp){ return(*funp)(a,b); } //usefunctionpointerasreturnvalue, statictwo_num_operationget_sum_fun(){ return∑ } //test-usefunctionpointerasvariable, voidtest_pointer_as_variable(){ //createapointertofunction, two_num_operationsum_p=∑ //callfunctionviapointer printf("pointerasvariable:\t%d+%d=%d\n",NUM_A,NUM_B,(*sum_p)(NUM_A,NUM_B)); } //test-usefunctionpointerasparam, voidtest_pointer_as_param(){ printf("pointerasparam:\t%d+%d=%d\n",NUM_A,NUM_B,sum_via_pointer(NUM_A,NUM_B,&sum)); } //test-usefunctionpointerasreturnvalue, voidtest_pointer_as_return_value(){ printf("pointerasreturnvalue:\t%d+%d=%d\n",NUM_A,NUM_B,(*get_sum_fun())(NUM_A,NUM_B)); } intmain(){ test_pointer_as_variable(); test_pointer_as_param(); test_pointer_as_return_value(); return0; } Share Improvethisanswer Follow editedJun8,2019at6:56 communitywiki 2revs,2users99%EricWang Addacomment  |  18 StartingfromscratchfunctionhasSomeMemoryAddressFromWhereTheystartexecuting.InAssemblyLanguageTheyArecalledas(call"function'smemoryaddress").NowcomebacktoCIffunctionhasamemoryaddressthentheycanbemanipulatedbyPointersinC.SoBytherulesofC 1.Firstyouneedtodeclareapointertofunction 2.PasstheAddressoftheDesiredfunction ****Note->thefunctionsshouldbeofsametype**** ThisSimpleProgrammewillIllustrateEveryThing. #include void(*print)();//DeclareaFunctionPointers voidsayhello();//DeclareTheFunctionWhoseAddressistobepassed //TheFunctionsshouldBeofSameType intmain() { print=sayhello;//Addressofsayhelloisassignedtoprint print();//printDoesAcallToTheFunction return0; } voidsayhello() { printf("\nHelloWorld"); } AfterThatletsSeeHowmachineUnderstandsThem.Glimpseofmachineinstructionoftheaboveprogrammein32bitarchitecture. Theredmarkareaisshowinghowtheaddressisbeingexchangedandstoringineax.Thentheirisacallinstructiononeax.eaxcontainsthedesiredaddressofthefunction. Share Improvethisanswer Follow editedJun8,2019at6:56 communitywiki 2revs,2users97%MohitDabas 1 HowdoIuseafunctionpointerreturnedfromamethod?something()seemstojustcrashtheprogram.Ihavesomecontextandfailedcodehere:stackoverflow.com/questions/67152106 – AaronFranke Apr18,2021at18:41 Addacomment  |  17 OneofthebigusesforfunctionpointersinCistocallafunctionselectedatrun-time.Forexample,theCrun-timelibraryhastworoutines,qsortandbsearch,whichtakeapointertoafunctionthatiscalledtocomparetwoitemsbeingsorted;thisallowsyoutosortorsearch,respectively,anything,basedonanycriteriayouwishtouse. Averybasicexample,ifthereisonefunctioncalledprint(intx,inty)whichinturnmayrequiretocallafunction(eitheradd()orsub(),whichareofthesametype)thenwhatwewilldo,wewilladdonefunctionpointerargumenttotheprint()functionasshownbelow: #include intadd() { return(100+10); } intsub() { return(100-10); } voidprint(intx,inty,int(*func)()) { printf("valueis:%d\n",(x+y+(*func)())); } intmain() { intx=100,y=200; print(x,y,add); print(x,y,sub); return0; } Theoutputis: valueis:410 valueis:390 Share Improvethisanswer Follow editedMar13,2019at17:09 communitywiki 3revs,3users76%Vamsi Addacomment  |  15 Afunctionpointerisavariablethatcontainstheaddressofafunction.Sinceitisapointervariablethoughwithsomerestrictedproperties,youcanuseitprettymuchlikeyouwouldanyotherpointervariableindatastructures. TheonlyexceptionIcanthinkofistreatingthefunctionpointeraspointingtosomethingotherthanasinglevalue.Doingpointerarithmeticbyincrementingordecrementingafunctionpointeroradding/subtractinganoffsettoafunctionpointerisn'treallyofanyutilityasafunctionpointeronlypointstoasinglething,theentrypointofafunction. Thesizeofafunctionpointervariable,thenumberofbytesoccupiedbythevariable,mayvarydependingontheunderlyingarchitecture,e.g.x32orx64orwhatever. ThedeclarationforafunctionpointervariableneedstospecifythesamekindofinformationasafunctiondeclarationinorderfortheCcompilertodothekindsofchecksthatitnormallydoes.Ifyoudon'tspecifyaparameterlistinthedeclaration/definitionofthefunctionpointer,theCcompilerwillnotbeabletochecktheuseofparameters.Therearecaseswhenthislackofcheckingcanbeusefulhoweverjustrememberthatasafetynethasbeenremoved. Someexamples: intfunc(inta,char*pStr);//declaresafunction int(*pFunc)(inta,char*pStr);//declaresordefinesafunctionpointer int(*pFunc2)();//declaresordefinesafunctionpointer,noparameterlistspecified. int(*pFunc3)(void);//declaresordefinesafunctionpointer,noarguments. Thefirsttwodeclararationsaresomewhatsimilarinthat: funcisafunctionthattakesanintandachar*andreturnsanint pFuncisafunctionpointertowhichisassignedtheaddressofafunctionthattakesanintandachar*andreturnsanint Sofromtheabovewecouldhaveasourcelineinwhichtheaddressofthefunctionfunc()isassignedtothefunctionpointervariablepFuncasinpFunc=func;. Noticethesyntaxusedwithafunctionpointerdeclaration/definitioninwhichparenthesisareusedtoovercomethenaturaloperatorprecedencerules. int*pfunc(inta,char*pStr);//declaresafunctionthatreturnsintpointer int(*pFunc)(inta,char*pStr);//declaresafunctionpointerthatreturnsanint SeveralDifferentUsageExamples Someexamplesofusageofafunctionpointer: int(*pFunc)(inta,char*pStr);//declareasimplefunctionpointervariable int(*pFunc[55])(inta,char*pStr);//declareanarrayof55functionpointers int(**pFunc)(inta,char*pStr);//declareapointertoafunctionpointervariable struct{//declareastructthatcontainsafunctionpointer intx22; int(*pFunc)(inta,char*pStr); }thing={0,func};//assignvaluestothestructvariable char*xF(intx,int(*p)(inta,char*pStr));//declareafunctionthathasafunctionpointerasanargument char*(*pxF)(intx,int(*p)(inta,char*pStr));//declareafunctionpointerthatpointstoafunctionthathasafunctionpointerasanargument Youcanusevariablelengthparameterlistsinthedefinitionofafunctionpointer. intsum(inta,intb,...); int(*psum)(inta,intb,...); Oryoucannotspecifyaparameterlistatall.ThiscanbeusefulbutiteliminatestheopportunityfortheCcompilertoperformchecksontheargumentlistprovided. intsum();//nothingspecifiedintheargumentlistsocouldbeanythingornothing int(*psum)(); intsum2(void);//voidspecifiedintheargumentlistsonoparameterswhencallingthisfunction int(*psum2)(void); CstyleCasts YoucanuseCstylecastswithfunctionpointers.HoweverbeawarethataCcompilermaybelaxaboutchecksorprovidewarningsratherthanerrors. intsum(inta,char*b); int(*psplsum)(inta,intb); psplsum=sum;//generatesacompilerwarning psplsum=(int(*)(inta,intb))sum;//nocompilerwarning,casttofunctionpointer psplsum=(int*(inta,intb))sum;//compilererrorofbadcastgenerated,parenthesisarerequired. CompareFunctionPointertoEquality YoucancheckthatafunctionpointerisequaltoaparticularfunctionaddressusinganifstatementthoughIamnotsurehowusefulthatwouldbe.Othercomparisonoperatorswouldseemtohaveevenlessutility. staticintfunc1(inta,intb){ returna+b; } staticintfunc2(inta,intb,char*c){ returnc[0]+a+b; } staticintfunc3(inta,intb,char*x){ returna+b; } staticchar*func4(inta,intb,char*c,int(*p)()) { if(p==func1){ p(a,b); } elseif(p==func2){ p(a,b,c);//warningC4047:'==':'int(__cdecl*)()'differsinlevelsofindirectionfrom'char*(__cdecl*)(int,int,char*)' }elseif(p==func3){ p(a,b,c); } returnc; } AnArrayofFunctionPointers Andifyouwanttohaveanarrayoffunctionpointerseachoftheelementsofwhichtheargumentlisthasdifferencesthenyoucandefineafunctionpointerwiththeargumentlistunspecified(notvoidwhichmeansnoargumentsbutjustunspecified)somethinglikethefollowingthoughyoumayseewarningsfromtheCcompiler.Thisalsoworksforafunctionpointerparametertoafunction: int(*p[])()={//anarrayoffunctionpointers func1,func2,func3 }; int(**pp)();//apointertoafunctionpointer p[0](a,b); p[1](a,b,0); p[2](a,b);//oops,leftoffthelastargumentbutitcompilesanyway. func4(a,b,0,func1); func4(a,b,0,func2);//warningC4047:'function':'int(__cdecl*)()'differsinlevelsofindirectionfrom'char*(__cdecl*)(int,int,char*)' func4(a,b,0,func3); //iterateoverthearrayelementsusinganarrayindex for(i=0;ihModule=LoadLibrary(dllFileName); if(pStruct->hModule){ pStruct->Func1=(int(*)())GetProcAddress(pStruct->hModule,"Func1"); pStruct->Func2=(int(*)())GetProcAddress(pStruct->hModule,"Func2"); pStruct->Func3=(int(*)(inta,intb))GetProcAddress(pStruct->hModule,"Func3"); retStatus=1; } returnretStatus; } voidFreeLibraryFunc(LibraryFuncStruct*pStruct) { if(pStruct->hModule)FreeLibrary(pStruct->hModule); pStruct->hModule=0; } andthiscouldbeusedasin: LibraryFuncStructmyLib={0}; LoadLibraryFunc(L"library.dll",&myLib); //.... myLib.Func1(); //.... FreeLibraryFunc(&myLib); Thesameapproachcanbeusedtodefineanabstracthardwarelayerforcodethatusesaparticularmodeloftheunderlyinghardware.Functionpointersarefilledinwithhardwarespecificfunctionsbyafactorytoprovidethehardwarespecificfunctionalitythatimplementsfunctionsspecifiedintheabstracthardwaremodel.Thiscanbeusedtoprovideanabstracthardwarelayerusedbysoftwarewhichcallsafactoryfunctioninordertogetthespecifichardwarefunctioninterfacethenusesthefunctionpointersprovidedtoperformactionsfortheunderlyinghardwarewithoutneedingtoknowimplementationdetailsaboutthespecifictarget. FunctionPointerstocreateDelegates,Handlers,andCallbacks Youcanusefunctionpointersasawaytodelegatesometaskorfunctionality.TheclassicexampleinCisthecomparisondelegatefunctionpointerusedwiththeStandardClibraryfunctionsqsort()andbsearch()toprovidethecollationorderforsortingalistofitemsorperformingabinarysearchoverasortedlistofitems.Thecomparisonfunctiondelegatespecifiesthecollationalgorithmusedinthesortorthebinarysearch. AnotheruseissimilartoapplyinganalgorithmtoaC++StandardTemplateLibrarycontainer. void*ApplyAlgorithm(void*pArray,size_tsizeItem,size_tnItems,int(*p)(void*)){ unsignedchar*pList=pArray; unsignedchar*pListEnd=pList+nItems*sizeItem; for(;pList



請為這篇文章評分?