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