C Programming Function Prototypes

Discussion in 'Mac Programming' started by cybrscot, Apr 4, 2011.

  1. macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #1
    My current book, "Learn C on the Mac" says that I should include a function prototype for every function, other than main(). But, in my other book "C Progamming, by K.N. King, I've gotten much further along than I have in this book and it never mentioned function prototypes at all, nor did any of the examples use them.

    Learn C on the Mac says that they help compilers know what's coming next in the code, but I never had any trouble when writing programs in my other book with my compiler knowing what's coming next or reading my code? Is this really necessary?

    Also please notice my comments below, and try to address my questions please


    Code:
    }		
    
    #include <stdio.h>
    
    void SayHello( void ) ;   //book says "other than main", isn't this f.proto for               
                                      //main??
    int main (int argc, const char* argv []) {  //this is main, right?? SayHello()
    	SayHello();                                  //is inside main's {}
    	
    	return 0;
    	
    }
    
    void SayHello( void ) {      //why here?? printf isn't a function, it's a stmt
    	printf("Hello, world!\n");
    	
    }
     
  2. AustinZ, Apr 4, 2011
    Last edited: Apr 4, 2011

    macrumors member

    AustinZ

    Joined:
    Aug 6, 2008
    #2
    It's at the very least good practice.

    Take the following sample code:

    Code:
    int main() {
        int a = 1;
        int b = 2;
    
        int c = functionA(a);
        functionB(a,b);
        functionC(b);
        (do more stuff...)
        return 0;
    }
    
    int functionA(int input) {
       return (input*input);
    }
    
    void functionB(int input) {
       (do stuff...)
    }
    
    void functionC(int input) {
       (do stuff...)
    }
    
    If you don't have the function prototypes many compilers will refuse to compile the code. This is because functionA, functionB, and functionC are called in main() before they have been defined. Having the function prototypes at the top tell the compiler what to expect when the code mentions functionA, functionB, and functionC.

    If you moved the main() function in the example to the bottom, the code would compile correctly. In this case, functionA, functionB, and functionC would be defined before any code actually called those functions (e.g. the code in main), and you wouldn't get errors. If you've been lucky so far and only called functions after you defined them you wouldn't get errors, even without function headers.

    Now imagine functionA called functionB, functionB called functionC, and functionC called functionA. In this situation you would need the function prototypes for things to compile correctly.

    In most cases the function prototypes are placed in a header (.h) file and included in the .c file (e.g. #include "myheader.h"). This also makes it easy for someone to see what functions are included in your module and how to invoke them; instead of wading through all your code in the .c file they can open the .h file and see all the short, concise function prototypes.

    ===================================

    As for your comments:

    1. The function prototype is for the SayHello function. Each function needs a function prototype, except for the main function.

    2. The function SayHello is not defined inside main(), it is called by main. 'SayHello();' basically means 'go to the SayHello function, execute all its code, and then return to where we were and continue executing. Main is defined from the curly bracket { to the curly bracket } (after 'return 0;'). SayHello is defined from the curly bracket { to the bracket }.

    3. printf is a function. The function is defined in the standard I/O library, which is why you did #include <stdio.h>.
     
  3. subsonix, Apr 5, 2011
    Last edited: Apr 5, 2011

    macrumors 68040

    Joined:
    Feb 2, 2008
    #3
    There are some options, either put the function prototype before main or put the entire function before main, or put it in a header file and include it just like stdio.h.

    All you would need to do is to leave it out, and observe the compile error. That should be confirmation that it's necessary in the example.

    BTW, regarding your comments, printf() is a function, it's defined in stdio.h so just like your sayhello() prototype it's introduced before main.
     
  4. macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #4
    Just in case it hasn't been clear, the compiler doesn't look ahead in your code.

    Take AustinZ's example. When the compiler is look at the line int c = functionA(a) is doesn't look further down your code to see how functionA is defined.

    Without a prototype before that line, it can't know how many paramaters there are meant to be, what are their types, and what is the type of the return value.

    For example, if functionA was actually defined as float functionA(float input), the compiler would need add instructions to convert the int a into a float and to covert the float return value into an int before assigning to c. Without the prototype, it could never know to do this.
     
  5. Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #5
    Exactly. I just posted something about this in cybrscot's "scope" thread.

    The function prototype is exactly analogous to a variable declaration.

    You would not assume that this code should work for exactly the same reason.

    Code:
    int a;
    a=b;
    int b;
    Just like you don't need a separate variable declaration, you don't need a separate function prototype. You can just put the code you need before where you use it, just as you can write int a = b + 1; without int a;.

    However, if you get into the habit it will make splitting your code into multiple files so much easier.

    B
     
  6. thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #6

    So just to clarify a bit more, printf is a funtion, AND.....it's also a string literal AND....it's also a statement right?? At least that's my understanding. I think in this book they said that printf is a statement too. I think in the past on these forums someone also said that printf is a string literal.

    If this is the case, then some of these things have different names and we refer to them by whichever name seems to fit the circumstances at the moment.
    Which is why I get confused from the books, because it seems sometimes they tell you that something is a function, or that a function is made of stmts, etc. So I end up changing what I think something is. Because I'm new at this, I'm not real confident in my knowledge yet. So I'll go along thinking something is a statement, then later I read it's a function, then I think I must have been wrong before in thinking it was a statement. And I say to myself, "oh I was wrong about that", it's really a function. etc. etc. etc.

    So some things in programming can be many things at once right?

    I hope somebody tells me I'm right about this!!
     
  7. macrumors regular

    Joined:
    Nov 24, 2006
    Location:
    The Netherlands
    #7
    I wouldn't call it a literal as it doesn't really 'hold' a value. However, it IS a function. Further you can consider every line of code you write as a statement.

    So:

    Code:
     
    int absValue = abs(-42);
    
    Is a statement. In this statement absValue is the literal and abs() is the function (and -42 is the function argument ;) ).
     
  8. Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #8
    printf is a function.

    The function prototype for the function printf is declared in <stdio.h> that is why you include it as AustinZ points out. (EDIT: you should open <stdio.h> for yourself and find the prototype.)

    When you call printf from your own code, that is a statement. e.g.
    Code:
    printf("Hello World!/n");
    In that particular case the string "Hello World!/n" is a string literal. It is not a variable holding the string, it literally is the string "Hello World!/n".

    Similarly:
    Code:
    int a = -42;
    int absValue_v = abs(a);
    int absValue_l = abs(-42);
    
    The argument to abs used to compute absValue_v is a variable named a that contains the value -42. The argument to abs used to compute absValue_l is a literal int whose value is -42.

    EDIT: This page http://c.comsci.us/etymology/literals.html defines it as:

    Once you type -42 or "Hello World!" that value is explicit (you know what it is) and invariant (it won't change). Other examples are in the link.

    B
     
  9. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #9
    I've arrived embarrassingly late to this particular rodeo, but i thought i'd throw in my 2¢ anyway (I am still regularly baffled by the lack of a "cent" sign in ascii).

    A function is a reusable piece of code that may take named arguments and may return a value. Note "may" doesn't mean "must", these pieces are optional. It's been laid out again, but hopefully more explanation doesn't muddy the water:
    A prototype describes the return type, name, and the number and type of arguments a function takes:
    int myNeatIntReturningFunction(char mySweetCharArgument, int *myExcellentIntPointerArgument, double myDubiousDoubleArgument);
    In this case the return type of the function is int, its name is myNeatIntReturningFunction, and it has three arguments, a char, an int *, and a double. You do not have to name your arguments in the prototype, just say what type they are, so:
    int myNeatIntReturningFunction(char, int *,double);
    would work just as well.

    A function implementation starts with a similar looking header, but also contains a block of code between {} that is the "function body", the code that executes when the function is called.
    Code:
    int myNeatIntReturningFunction(char mySweetCharArgument, int *myExcellentIntPointerArgument, double myDubiousDoubleArgument) {
      int returnValue = 0;
      if(myDubiousDoubleArgument > 87.32) {
        returnValue += 22;
      }
    
      returnValue -=*myExcellentIntPointerArgument;
    
      if(mySweetCharArgument >= 'A' && mySweetCharArgument <= 'Z') {
        returnValue = mySweetCharArgument + ('a' - 'A');
      }
    
      if(returnValue > *myExcellentIntPointerArgument) {
        *myExcellentIntPointerArgument = returnValue;
      }
    
      return returnValue;
    }
    
    Earlier you stated that printf was a "string literal". I'm not sure what you meant, but it certainly isn't that. It's first argument is often a string literal, but could also be a const char * variable. A literal is any of these:
    1
    5.6f
    5.6
    'A'
    "A"
    45L
    12U

    They are different types of literals, but literal means: exactly this value of a particular data type. This means the value of this expression is known at compile-time. The type of printf is int, so it doesn't even return a string.

    When you call a function, you pass it the proper arguments, and you can assign or test its return value. There are times that a function will do something very fixed and specific, like print a banner for example, that requires no input and no return value. This is pretty rare, though, as what really makes functions interesting is they allow you to perform a task on different data and get a result. Often the result will be returned from the function, but (I can't remember if you've covered pointers yet) you can also modify variables that are passed to a function using a pointer.

    Again, most of this has been mentioned, but while I'm here... The reason for prototypes is to tell the compiler in advance what a function "looks like". It's going to make assumptions if you don't give it the heads up, and it may give you warnings it should not based on these assumptions, or fail to give you warnings it should. We want to tell the compiler the most we possibly can so it can tell us the most it possibly can about potential problems. Any issue you can catch and fix at compile time is a great boon compared to having to figure it out at runtime. When we tell the compiler about our functions it can check that we're passing the right number and type of arguments, it can tell us about possibly unexpected data-conversion issues with a return type (assigning the result of a function that returns a double to an int, for example), and it's generally happier because it's well-informed.

    Functions are absolutely critical to modularity. They allow us to write solid, well-tested code that we're confident performs a task correctly, and then reuse this code all over our program or throughout all of our programs. We depend on system-provided functions to get anything useful done (like your printf example). If you ever find yourself retyping or copying/pasting code from one place to another you should probably be pasting it into a function, genericizing as needed, and using the function instead.

    -Lee
     
  10. macrumors 6502

    Joined:
    Apr 29, 2010
    #10
    You probably need prototypes when you're going to write mutually recursive functions.
     
  11. Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #11
    I think you are right about that.

    If function1 calls function2 and function2 calls function1 (defining mutual recursion for those who may not have understood what you meant). You need to tell the compiler what to expect for each function before it's called using prototypes.

    So unless you can write your code on a Moebius strip, and your compiler can read it that way you probably need prototypes. :p

    B
     
  12. thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #12
    It was mentioned by balamw that I should "open" <stdio.h> and look at the function prototypes included.

    I never knew one could "open" <stdio.h>, I just thought it was a piece of code that started off each program, that included the standard library from somewhere deep inside my computer, I had no idea where it was or that you could "look inside" Shows how much I know!! Everyday something new out of left field!! My books have just said it was standard library..... the C Programming by KN King never mentioned func. proto, as of yet, ch 7.

    So how do I open it?

    Also, my current book, Learn C on the Mac, says explicitly I should include function prototypes for all functions except main (). This is pretty literal, and it never said that printf already has it's func proto included in <stdio.h>. So how was I to know this? Thanks to you guys for telling me that!

    This is bringing me to my next dilemma, since even printf is a function, how do I know which functions (other than printf) have their func proto's included in a header, or that I need to write the func proto myself?? ?? Listening to the book, now I'm thinking that it's good practice to use func proto's as they recommend, but after you guys told me that printf was a function, I was wondering why the book didn't show a proto for printf, then I learned from you guys, (not the book) that <stdio.h> already contained the proto for printf!!
     
  13. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #13
    You need to write prototypes for functions YOU write. If you are using a function from a library you only know it's arguments, return type, etc. because it was included in a header. You're not capable of writing the prototype yourself because you don't have the necessary information. When you write a function, always remember that an important step is to put the prototype at the top of your source file or in a header file that you're including.

    From terminal, you can type "locate stdio.h". You may end up getting a few matches, but for your purposes any are fine. I'm not sure if you're comfortable with any terminal text editors, but once you've found the location of the file hopefully you can open it in whatever you like.

    -Lee
     
  14. macrumors 6502

    Joined:
    Apr 29, 2010
    #14
    Thanks for explaining what I meant.

    What's a moebius strip? If a moebius is going to take off his clothes, I don't want to watch. :eek::p
     
  15. macrumors 68000

    ulbador

    Joined:
    Feb 11, 2010
    #15
    It's in the directory:

    /usr/include



    Opening the file may not be enough to get a handle on what's in it. It's not really documented. You are better off just plugging stdio.h into google and looking at some of the very well documented reference material that's out there:

    http://www.cplusplus.com/reference/clibrary/cstdio/
     
  16. firestarter, Apr 5, 2011
    Last edited: Apr 5, 2011

    macrumors 603

    firestarter

    Joined:
    Dec 31, 2002
    Location:
    Green and pleasant land
    #16
    You won't appreciate the value of function prototypes so much when you're writing small self contained programs - their value increases as you build bigger systems with multiple files of source code.

    Function prototypes, held in their own .h 'header' files allow you to compile against a function, without the compiler actually parsing that function's code. The result of this is that you can pre-compile all your libraries and separate code modules into 'object' files, and you don't have to keep re-compiling them. This is a BIG WIN if you're writing a large app, or using other people's libraries in your code.

    It also enables you to ship libraries as compiled object code + header files, without including the source code too. This is essential for 3rd party libraries who don't necessarily want to share their source code. To use these libraries, you just #include the header file.

    The app whose job it is to join all these pieces of individual object code together after compilation is the linker.
     
  17. balamw, Apr 5, 2011
    Last edited: Apr 5, 2011

    Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #17
    Yeah, perhaps something simpler like stdbool.h from the other thread might be easier to grok. I keep forgetting how complicated I/O (particularly scanf/printf) can really be:

    FWIW the prototype for printf in /usr/include/stdio.h on my system is:

    Code:
    int      printf(const char * __restrict, ...) __DARWIN_LDBL_COMPAT(printf);
    When you #include a header file it is basically like copying and pasting the entire document in your .c file at that point from the compiler's perspective. So if the file you #include has #includes of its own, all of that will get processed. So __DARWIN_LDBL_COMPAT is probably defined in one of those #includes.

    You can also get something easier to digest from the man pages on your own system. Try "man 3 printf" from Terminal and among other things you'll see:

    Code:
    int
         printf(const char *restrict format, ...);
    http://en.wikipedia.org/wiki/Möbius_strip perfectly safe for work.

    B
     
  18. macrumors 603

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #18
    There are tons of recommended programming practices that aren't really needed, until your programs become much larger and in need of maintenance or reuse, etc.

    My preferred suggestion is to forget about them until you encounter your first nasty bug that could have been avoided had you used this software methodology. Then you will know why. Programming is hard enough to learn at all, without having to learn how to program "correctly" at the same time.
     
  19. thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #19
    I need some help figuring out what is what below...

    void SquareIt (); is the function prototype right? And it's giving the compiler a preview of the very next line, int main () {, correct?? As my book says to use a f proto before each function.

    If I was writing that f.proto, how would I know to write the SquareIt after the void?? Meaning, why chose the word SquareIt?? What does that tell the compiler? That word isn't in the int main () line of code anywhere.




    Code:
    #include <stdio.h>
    
    	void   SquareIt ( int number, int *squarePtr); //this is a f. proto, yes??
    	                                                         
    	int main (int argc, const char * argv []) { //the f proto is giving the 
    		int   square;                              //compiler a prev of this line??
    		
    		SquareIt(5, &square); // I understand these are parameters
    		
    		printf("5 squared is %d.\n", square);
    		
    		return 0;
    		
    	}
    	
    	void	SquareIt(int number, int *squarePtr) { //is this another f. proto?
    		*squarePtr = number * number;         //what does this entire piece 
    		                                                     //of code do?? It's after the 
    	                                                             //program has ended.
    }	

    Do you usually write the f proto after you have written the function? Typically, I have written my programs line by line from the top down, but it seems that one would need to write the function first, than go back and insert a f proto above it.
     
  20. macrumors 68040

    Joined:
    Feb 2, 2008
    #20
    Yes it's a function prototype. It's telling the compiler that the function SquareIt inside main has an implementation further down. It's known as forward declaration, it's the same principle you use when you declare a variable without defining it, as was mentioned earlier. For example:

    Code:
    int a;
    a = 10;
    
    Works, but:

    Code:
    a = 10;
    int a;
    
    doesn't

    Yes SqurareIt is in main, it's just above printf. Without the prototype the compiler won't know what to do with SquareIt, (unless you move the entire function up before main). The name SquareIt is completely arbitrary, it's just an identifier like a variable name. You can make up anything you want as long as you don't give your function a name that already exists.
     
  21. macrumors regular

    Joined:
    Nov 24, 2006
    Location:
    The Netherlands
    #21

    Code:
    #include <stdio.h>
    
    	void   SquareIt ( int number, int *squarePtr); //this is a f. proto, yes??
    	                                                         
    // Yup, that is the function prototype. This tells the compiler that a function 
    // exists which returns a void and takes a number and a pointer to a number.
    
    // Nothing more.
    
    
    
    	int main (int argc, const char * argv []) { //the f proto is giving the 
    		int   square;                              //compiler a prev of this line??
    
    // No. This line has nothing to do with the prototype definition above
    		
    	
    	void	SquareIt(int number, int *squarePtr) { //is this another f. proto?
    
    // No. This is the function definition. It is basically the real world function 
    // you told the compiler that existed in the function prototype above. 
    
    // As you can see it looks just like the prototype but instead of closing 
    // the line with a ; you open a new scope (the function) by typing a {
    
    		*squarePtr = number * number;         //what does this entire piece 
    		                                                     //of code do?? It's after the 
    	                                                             //program has ended.
    }	
    
    // I think you might be thinking about it wrong. Your program isn't executed top-down, 
    // line by line. The program can jump between functions and back. See below.
    
    Flow:

    Just to explain what happens. Your program runs into line 1, it sees the functions SquarIt.

    It then jumps in you program to the function squareIt (which you declared below your main) and
    executes the code in there. When it's at the end of that function the program goes back to line 2
    and executes that.
     
  22. thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
  23. Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #23
    cybrscot,

    The code you posted is equivalent to:

    Code:
    #include <stdio.h>
    	                                                         
    int main (int argc, const char * argv []) { 
    	int   square;                              	
    	square = 5 * 5;
    		
    	printf("5 squared is %d.\n", square);
    		
    	return 0;
    }
    
    They introduced a function to implement the line square = 5*5 that passes the argument (5) by value and square by reference. Then, since the code for the function SquareIt was below main they added a function prototype for SquareIt above main so the compiler would know what was coming.

    This is often how code evolves.

    You identify a bit of your code that you want to encapsulate for some reason. Either you use it a lot in this code, you want to reuse it in some other code or it is messy and you want to separate it from the main logic flow of your program.

    These small scale examples are never ideal as the thing they are equivalent to is often less complex than the version that includes functions and function prototypes.

    Note that the function prototype and the function declaration must agree on several things: The function's name, the function's return type, the number of arguments the function takes and the data types of those arguments. They do not have to agree about the argument names, just like when you call the function you don't have to use the same names.

    In this case you can read the function prototype as saying: There is a function called SquareIt coming up somewhere. It takes two arguments one int by value and one int by reference and returns nothing. At that point that is all either you or the computer know about this function.

    B
     
  24. thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #24
    This is exactly what I was thinking after seeing your code. Your code, looks like something I could write already based on my knowledge so far, so I was thinking if it can be done this easily, why bother with the confusion of pointers? Are we just trying to make ourselves look clever? But I get what you mean, it's just an example, albeit one that can be done an easier way, but it's not like they are going to use a huge complicated program to teach a concept to a beginner, or we'd never understand it and have a million more questions. Thanks
     
  25. macrumors 603

    notjustjay

    Joined:
    Sep 19, 2003
    Location:
    Canada, eh?
    #25
    Exactly. There are lots of very good reasons for using pointers, but you won't see them until you start working with bigger, more complex programs. You'll start creating and destroying data on-the-fly (using malloc() for example) and you'll start working with entire data structures instead of simple variables. Once you start getting into object-oriented programming, you'll start using them even more.
     

Share This Page