Thread: Passing functions as parameters in other functions

  1. #1
    Registered User
    Join Date
    Apr 2006
    Posts
    4

    Passing functions as parameters in other functions

    Passing functions as parameters

    Hello,

    I am having trouble understanding how some code works for a project of mine. I don't quite get how passing a function as a parameter into another function works. Here is the code im referring to:

    Code:
    void tftp_connection(struct sockaddr_in *serveraddr,char *action,char *name, char *readname)
    {
        FILE *f;
        int blen=255;
        
        if ((action[0]=='R')||(action[0]=='r')) {
        
            f=fopen(name,"wb");
    	
    		if (readname==NULL)  
    			blen=tftp_receive(serveraddr,name,"octet",1,TFTPswrite,f);
    		else 
    			blen=tftp_receive(serveraddr,readname,"octet",1,TFTPswrite,f);
    		
            fclose(f);
        }
        
        if (blen!=0) 
        	printf("tftp error. please try again.\n\n");
    }
    
    int tftp_receive(struct sockaddr_in *to1,char *name,char *mode,int innum,                
                     char (*TFTPwrite)(char *,long ,char,void *),
                     void *argu)
    {
        return tftp_receive_ext(to1,name,mode,innum,TFTPwrite,argu,PKTSIZE);
    }
    
    char TFTPswrite(char *data,long n,char first,void *f)
    {
        fwrite(data,n,1,(FILE *)f);
        return 0;
    }
    The question i have is that when you pass TFTPswrite as a parameter in both:

    Code:
    blen=tftp_receive(serveraddr,name,"octet",1,TFTPswrite,f);
    return tftp_receive_ext(to1,name,mode,innum,TFTPwrite,argu,PKTSIZE);
    how does it know what parameters to use for the function since we are just passing the name of the function? TFTPwrite uses data, n, and *f, but when we call the function (tftp_receive and tftp_receive_ext respectively) that passes TFTPswrite as a function where is it pulling these values for TFTPswrite to use from (char *data,long n,char first,void *f)?

    I also have a question as to when the code for TFTPswrite executes. Does it execute when it is passed in as a parameter? Would there be another way to not pass TFTPswrite as a parameter and just have the one line of code it uses execute somewhere else in the program so that we can avoid passing it as a parameter?

    Any help would be greatly appricated i know it sounds confusing me trying to explain but i think the code is even more confusing.


    '

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > char TFTPswrite(char *data,long n,char first,void *f)
    Matches the parameter in the function prototype
    > char (*TFTPwrite)(char *,long ,char,void *)
    That's how a function knows how to call another function, when it's only been passed a pointer.

    > Does it execute when it is passed in as a parameter?
    No, it executes when a function uses that parameter in the context of a function call.

    Perhaps a simple example will help
    Code:
    #include <stdio.h>
    
    int add ( int a, int b ) {
      return a + b;
    }
    int sub ( int a, int b ) {
      return a - b;
    }
    int calc ( int a, int b, int (*op)(int,int) ) {
      /* op is a pointer to a function.  By specifying the pointer name */
      /* with following (), we're calling the function passes as a parameter! */
      return op(a,b);
    }
    
    int main ( void ) {
      int v1 = 10, v2 = 5;
      printf( "%d + %d = %d\n", v1, v2, calc(v1,v2,add) );
      printf( "%d - %d = %d\n", v1, v2, calc(v1,v2,sub) );
      return 0;
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Apr 2006
    Posts
    4
    ok but i still don't get it in the code i gave you...i see that you are actually calling op when you call retun op(a,b). But in the code i gave you, it never actually calls TFTPswrite, it just passes it as a function. There is no where in teh code that says TFTPswrite(x,x,x,x) or whatever. So does that mean that TFTPswrite isn't actually being called or does it run whenever it is being passed as a parameter?

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Well it gets passed to tftp_receive_ext(), which I imagine would call it.
    But you didn't post that function.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Apr 2006
    Posts
    4
    ok sorry i should have posted the other function. Here it is:

    Code:
    int tftp_receive_ext(struct sockaddr_in *to1,char *name,char *mode,int innum,                
                         char (*TFTPwrite)(char *,long ,char,void *),
                         void *argu,int vPKTSIZE)
    {
        char *buf, *ackbuf, *dat, *cp;
        struct tftphdr *datapacket, *ackpacket;
        int i, size, n, nto, ptp;
        struct timeval tv;
        u_short nextsegnum;
        fd_set fdfileset;
        struct sockaddr_in from,to=*to1;
        size_t fromlen=sizeof(from),tolen=fromlen;
        
        buf = (char*)malloc(vPKTSIZE);
        if (buf==NULL) {
            fprintf(stderr,"TFTP: out of memory.\n");
            return 255;
        }
    
        ackbuf=(char*)malloc(vPKTSIZE);
    
        if (ackbuf==NULL) {
            fprintf(stderr,"TFTP: out of memory.\n");
            free(buf);
            return 255;
        }
    
        datapacket = (struct tftphdr *)buf;
        ackpacket = (struct tftphdr *)ackbuf;
        dat = (char*)&datapacket->th_data[0];
        cp = (char*)&ackpacket->th_stuff[0];
    
        i=0;
    
        if ((ptp=create_socket(SOCK_DGRAM, &i, NULL))<0) {
            syslog(1,"creation socket client: %m\n");
            free(buf); free(ackbuf);
            return 255;
        }
              
        if (innum) {
            ackpacket->th_opcode=htons((u_short)RRQ);
            strcpy(cp, name);
        	cp += strlen(name);
    	    *cp++ = '\0';
    	    strcpy(cp, mode);
        	cp += strlen(mode);
        	*cp++ = '\0';
            size=(DWORD)cp-(DWORD)ackbuf;
        } 
    	else {
            ackpacket->th_opcode=htons((u_short)ACK);
            ackpacket->th_block=0;
            size=4;
        }
    
        nextsegnum=1;
        
        do  {    
          nto=0;
          do {
    
             if (nto==numTimeOut) { 
    			 close(ptp); 
    			 free(buf); 
    			 free(ackbuf); 
    			 return 255;
    		 }
    
             if (sendto(ptp,ackpacket,size,0,(struct sockaddr *)&to,tolen)!=size)
             {
                 syslog(1, "tftp is writing: %m\n");
                 close(ptp);  
    			 free(buf); 
    			 free(ackbuf);
                 return 255;
             }
    
             do {
                 n=-1;
    	         FD_ZERO(&fdfileset);
    	         FD_SET(ptp,&fdfileset); 
    	         tv.tv_sec=TimeOut; tv.tv_usec=0;
    	         if ((i=select(ptp+1, &fdfileset, NULL, NULL, &tv))==-1) {
    	            syslog(1,"select error.\n");
    	            close(ptp); 
    				free(buf); 
    				free(ackbuf);
    	            return 255;
    	         }
    	         if (i>0) 
    				 n=recvfrom(ptp, datapacket, vPKTSIZE, 0,(struct sockaddr *)&from, &fromlen);
    	     } while ((n<0)&&(i>0));
    
             if (i>0) {
    
                to.sin_port=from.sin_port;
                datapacket->th_opcode = ntohs((u_short)datapacket->th_opcode);            
                datapacket->th_block = ntohs((u_short)datapacket->th_block);
    
                if (datapacket->th_opcode != DATA) {
                    close(ptp); free(buf); free(ackbuf);
                    return 255;
                }
            
                if (datapacket->th_block != nextsegnum) {
                   ioctl(ptp, FIONREAD, &i); 
                   while (i)
                   {
                      recv(ptp, datapacket, vPKTSIZE, 0);
                      ioctl(ptp, FIONREAD, &i);
                   };
                   datapacket->th_block=nextsegnum+1;
                }
             }
             nto++;
          } while (datapacket->th_block!=nextsegnum);
    
          ackpacket->th_block=htons(nextsegnum);
          nextsegnum++;
    
          if (nextsegnum==2) {
              ackpacket->th_opcode=htons((u_short)ACK);
              size=4;
          }
    
          if (n-4>0)
          {
              if (nextsegnum==2) 
    			  i=(*TFTPwrite)(dat,n-4,1,argu);
              else 
    			  i=(*TFTPwrite)(dat,n-4,0,argu);
              if (i) {
                   close(ptp); free(buf); free(ackbuf);
                   return i;
              }
          }
     
       } while (n == vPKTSIZE);
    
       sendto(ptp, ackpacket, 4, 0,(struct sockaddr *)&to,tolen);
       close(ptp); 
       free(buf); 
       free(ackbuf);
       return 0;
    }

  6. #6
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> So does that mean that TFTPswrite isn't actually being called or does it run whenever it is being passed as a parameter?

    maybe here:

    >> i=(*TFTPwrite)(dat,n-4,1,argu);

    which can be called simply as:

    Code:
    i=TFTPwrite(dat,n-4,1,argu);
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  7. #7
    Registered User
    Join Date
    Apr 2006
    Posts
    4
    Quote Originally Posted by Sebastiani
    maybe here:

    >> i=(*TFTPwrite)(dat,n-4,1,argu);

    which can be called simply as:

    Code:
    i=TFTPwrite(dat,n-4,1,argu);

    Even more simply, couldn't i just get rid of the TFTPswrite function all together since it only has one line of code...all this complication of typecasting and passing pointers and other stuff seems pointless if it is just doing one line of code...would it work the same way if i just did this (code is from last part of tftp_receive_ext but modified to do as stated above):

    Code:
          if (n-4>0) {
              if (nextsegnum==2) 
    		      i = fwrite(dat,n-4,1,(FILE *)argu);
              else 
    		      j = fwrite(dat,n-4,0,(FILE *)argu);
    
              if (i < 1 || j < 0) {
                   close(ptp); 
    			   free(buf); 
    			   free(ackbuf);
                   return i;
              }
          }
    Here is the previous code so you can easily note the changes:
    Code:
          if (n-4>0)
          {
              if (nextsegnum==2) 
    			  i=(*TFTPwrite)(dat,n-4,1,argu);
              else 
    			  i=(*TFTPwrite)(dat,n-4,0,argu);
              if (i) {
                   close(ptp); free(buf); free(ackbuf);
                   return i;
              }
          }
    I'm using i and j for the variables because fwrite returns a value less than count (which is the 3rd paramter passed in fwrite) if an error comes up; count is either 1 or 0 as you can see in the code.

    So do you think its better to remove that function and will this work properly if i do?

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > So do you think its better to remove that function and will this work properly if i do?
    Presumably, the idea is different functions can be plugged in later on, in which case assuming that it's always that would be wrong.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Passing parameters between templated functions
    By SpaceCadet in forum C++ Programming
    Replies: 1
    Last Post: 11-20-2006, 03:57 PM
  2. Passing pointers between functions
    By heygirls_uk in forum C Programming
    Replies: 5
    Last Post: 01-09-2004, 06:58 PM
  3. Passing Parameters
    By fry in forum C++ Programming
    Replies: 2
    Last Post: 10-04-2002, 03:06 AM
  4. Passing data/pointers between functions
    By TankCDR in forum C Programming
    Replies: 1
    Last Post: 11-02-2001, 12:59 AM
  5. passing functions with variable
    By itld in forum C++ Programming
    Replies: 1
    Last Post: 10-30-2001, 11:43 PM