Function Prototypes: Necessary or just good practice?

Discussion in 'C Programming' started by /dev/phaeton, Feb 14, 2012.

  1. /dev/phaeton

    /dev/phaeton Guest

    In K&R2, function definitions in a program were preceded by a function
    prototype, i.e.:

    int my_function(int variable1, int variable2);

    Then somewhere down the line is the actual definition of the function
    itself:

    int my_function(int variable1, int variable2)
    {
    do;
    some;
    stuff;
    return (some_value);
    }


    However, I've noticed that if I omit the function prototype, the program
    compiles (with gcc 4.6.x at least) and runs just fine. Is this
    something that's now acceptable in ANSI standards since K&R2 was
    printed? Or is this 'compiler forgiveness'- letting me do something I
    probably shouldn't?


    Thanks.

    -J
     
    /dev/phaeton, Feb 14, 2012
    #1
    1. Advertising

  2. /dev/phaeton wrote:
    > In K&R2, function definitions in a program were preceded by a function
    > prototype, i.e.:
    >
    > int my_function(int variable1, int variable2);
    >
    > Then somewhere down the line is the actual definition of the function
    > itself:
    >
    > int my_function(int variable1, int variable2)
    > {
    > do;
    > some;
    > stuff;
    > return (some_value);
    > }
    >
    >
    > However, I've noticed that if I omit the function prototype, the program
    > compiles (with gcc 4.6.x at least) and runs just fine. Is this something
    > that's now acceptable in ANSI standards since K&R2 was printed? Or is
    > this 'compiler forgiveness'- letting me do something I probably shouldn't?
    >
    >
    > Thanks.
    >
    > -J


    Hello,

    in a sense your function definition includes the prototype..
    As long as any function that calls it is further down the file,
    there will not be any problems.

    methinks the prototype(only) would be

    int my_function(int, int);

    and the definition(minimum required) would be:

    my_function(variable1, variable2)
    {

    }

    if there's no prototype, AFAIK
    some assumptions regarding the types
    are made by the compiler. It assumes int as return type
    and ints for any parameters specified (unless it's pointers
    then it is pointers to int).
    so for above example you get something like the following:

    int my_function(int,int)

    which just happens to be your original declaration.

    This raises a question..
    Why prototypes?
    Including type information in function definitions increases
    readability and is completely alright for static functions
    as long as any functions that call it are further down the file.
    However, this usually reverses the 'logical' order of function
    definitions inside a file, so lowest level functions show up
    first.
    That is why most people explicitly specify prototypes also
    for static functions.

    They are usually needed for extern functions to be used with
    header files, of course.

    Warning: above is mostly how I understand C99, I do not know
    too much about K&R C. So take it with a grain of salt.

    bye,
    JK
     
    Johann Klammer, Feb 14, 2012
    #2
    1. Advertising

  3. On 13-Feb-12 23:05, /dev/phaeton wrote:
    > In K&R2, function definitions in a program were preceded by a function
    > prototype, i.e.:
    >
    > int my_function(int variable1, int variable2);


    Note this is a prototyped function _declaration_.

    > Then somewhere down the line is the actual definition of the function
    > itself:
    >
    > int my_function(int variable1, int variable2)
    > {
    > do;
    > some;
    > stuff;
    > return (some_value);
    > }


    This is a prototyped function _definition_. Note that a definition
    declares the function as well, if that hasn't already been done.

    > However, I've noticed that if I omit the function prototype,


    ITYM the function declaration.

    > the program compiles (with gcc 4.6.x at least) and runs just fine.


    Since you don't include the rest of the program's source, we don't know
    if this is luck or you just didn't happen to do something wrong.

    Lots of stuff happens to work "just fine" on some implementations even
    though that may not be guaranteed.

    > Is this something that's now acceptable in ANSI standards since K&R2
    > was printed? Or is this 'compiler forgiveness'- letting me do something I
    > probably shouldn't?


    It's not new; in fact, it's the old (pre-ANSI) way of doing things.

    K&R C allowed calling functions that hadn't previously been declared,
    which caused an implicit declaration of a function by that name. This
    was deprecated by ANSI. Unless you _know_ you are coding for a platform
    for which there is no C89 (or later) compiler, which should be
    incredibly rare these days, you should always declare your functions.

    S

    --
    Stephen Sprunk "God does not play dice." --Albert Einstein
    CCIE #3723 "God is an inveterate gambler, and He throws the
    K5SSS dice at every possible opportunity." --Stephen Hawking
     
    Stephen Sprunk, Feb 14, 2012
    #3
  4. /dev/phaeton

    Philip Lantz Guest

    /dev/phaeton wrote:
    > In K&R2, function definitions in a program were preceded by a function
    > prototype, i.e.:
    >
    > int my_function(int variable1, int variable2);
    >
    > Then somewhere down the line is the actual definition of the function
    > itself:
    >
    > int my_function(int variable1, int variable2)
    > {
    > do;
    > some;
    > stuff;
    > return (some_value);
    > }
    >
    >
    > However, I've noticed that if I omit the function prototype, the program
    > compiles (with gcc 4.6.x at least) and runs just fine. Is this
    > something that's now acceptable in ANSI standards since K&R2 was
    > printed? Or is this 'compiler forgiveness'- letting me do something I
    > probably shouldn't?


    1. If all calls to the function are after the definition, then the
    definition acts as a prototype and there is no problem. The following
    points are based on the assumption that there is a call before the
    definition.

    2. It's allowed by the C90 standard, as long as the function returns int
    and the correct parameters are passed. The number and types of
    parameters are not checked, and the behavior is undefined if they don't
    match the function definition (based on a non-trivial set of matching
    rules in the standard).

    3. It's not allowed by C99 and later standards. Many compilers may still
    support it, though, for backward compatibility.

    4. It is letting you do something you probably shouldn't--even when the
    behavior is allowed and defined by the standard, it is much better to
    always have a prototype-style definition or declaration of every
    function before it is called.
     
    Philip Lantz, Feb 14, 2012
    #4
  5. /dev/phaeton

    Kaz Kylheku Guest

    On 2012-02-14, /dev/phaeton <blahbleh666@no_more_spam.hotmail.com> wrote:
    > In K&R2, function definitions in a program were preceded by a function
    > prototype, i.e.:


    It's good practice to declare functions before calling them.
    Calling undeclared functions is a deprecated language feature.

    However, there is often no need for prototypes within one translation unit,
    because you can organize the code so that each function is defined prior to any
    calls to the function. A function definition serves as a prototype declaration.

    This arrangement is impossible when you have mutual recursion among
    two or more functions. Some of them have to be prototyped.

    > However, I've noticed that if I omit the function prototype, the program
    > compiles (with gcc 4.6.x at least) and runs just fine.


    With what warning options?

    How about with -Wall and -W?
     
    Kaz Kylheku, Feb 14, 2012
    #5
  6. Johann Klammer <1.net> writes:

    > /dev/phaeton wrote:
    >> In K&R2, function definitions in a program were preceded by a function
    >> prototype, i.e.:
    >>
    >> int my_function(int variable1, int variable2);
    >>
    >> Then somewhere down the line is the actual definition of the function
    >> itself:
    >>
    >> int my_function(int variable1, int variable2)
    >> {

    <snip>
    >> }
    >>

    <snip>
    > in a sense your function definition includes the prototype..
    > As long as any function that calls it is further down the file,
    > there will not be any problems.
    >
    > methinks the prototype(only) would be
    >
    > int my_function(int, int);


    That's fine, but so is the longer form with named parameters given by
    the OP.

    > and the definition(minimum required) would be:
    >
    > my_function(variable1, variable2)
    > {
    >
    > }


    No, that's not allowed. First, in C99, you are not allowed to omit the
    return type. Even in older C (where the implicit int return is OK), the
    parameters must be declared either in the function declarator (that's
    what the OP did and is the modern way) or in a separate declaration list
    between the ) and the { like this:

    my_function(variable1, variable2)
    int variable1, variable2;
    {
    }

    This last form is old K&R C and was still legal in C90. Add "int" for
    the return type and it's still legal in C99 (though very bad style
    nowadays).

    > if there's no prototype, AFAIK
    > some assumptions regarding the types
    > are made by the compiler. It assumes int as return type


    In C90 ("ANSI C") yes. In C99 implicit declarations are not permitted.

    > and ints for any parameters specified (unless it's pointers
    > then it is pointers to int).
    > so for above example you get something like the following:
    >
    > int my_function(int,int)


    No, you get int my_function() and there is a real difference. You are
    confusing what are called the default argument promotions with an
    implied prototype. When there's no prototype, the compiler assumes
    nothing about the parameters, but it does perform certain type
    conversions in a call. If the compiler assumed the prototype you've
    written, a call like my_function(1.0, 2.0) would have the
    arguments converted, but that's not what happens. The details hardly
    matter, since this is only important for very old code.

    > which just happens to be your original declaration.
    >
    > This raises a question..
    > Why prototypes?
    > Including type information in function definitions increases
    > readability and is completely alright for static functions
    > as long as any functions that call it are further down the file.


    They (prototypes) also cause correct conversion of function arguments.
    You don't get that with non-prototype declarations or definitions.

    <snip>
    --
    Ben.
     
    Ben Bacarisse, Feb 14, 2012
    #6
  7. Ben Bacarisse <> wrote:

    > No, that's not allowed. First, in C99, you are not allowed to
    > omit the return type. Even in older C (where the implicit int
    > return is OK), the parameters must be declared either in the
    > function declarator (that's what the OP did and is the modern
    > way) or in a separate declaration list between the ) and the {
    > like this:
    >
    > my_function(variable1, variable2)
    > int variable1, variable2;
    > {
    > }
    >


    I still remember that I used to write
    "main (argc, argv) char **argv; { /* some work */ return 0; }".

    And C90 did not break such existing code omitting an implicit int
    declaration:

    | If the declarator includes an identifier list, the types of the
    | parameters may be declared in a following declaration list. Any
    | parameter that is not declared has type int.

    -- Ralf
     
    Ralf Damaschke, Feb 14, 2012
    #7
  8. Ben Bacarisse <> wrote:
    > In C99 implicit declarations are not permitted.


    They're no longer required, but if a C99+ implementation
    decides to support them anyway, no diagnostic is required
    for their use.

    ....
    > They (prototypes) also cause correct conversion of function
    > arguments. ...


    Unless the prototype ends with ellipsis and you're back to
    default argument promotions for the unnamed arguments.

    --
    Peter
     
    Peter Nilsson, Feb 14, 2012
    #8
  9. /dev/phaeton

    James Kuyper Guest

    On 02/14/2012 04:47 PM, Peter Nilsson wrote:
    > Ben Bacarisse <> wrote:
    >> In C99 implicit declarations are not permitted.

    >
    > They're no longer required, but if a C99+ implementation
    > decides to support them anyway, no diagnostic is required
    > for their use.


    Its a constraint violation - 6.7.2p2: "At least one type specifier shall
    be given in the declaration specifiers in each declaration,
    and in the specifier-qualifier list in each struct declaration and type
    name." Therefore a diagnostic is required.
     
    James Kuyper, Feb 14, 2012
    #9
  10. James Kuyper <> writes:

    > On 02/14/2012 04:47 PM, Peter Nilsson wrote:
    >> Ben Bacarisse <> wrote:
    >>> In C99 implicit declarations are not permitted.

    >>
    >> They're no longer required, but if a C99+ implementation
    >> decides to support them anyway, no diagnostic is required
    >> for their use.

    >
    > Its a constraint violation - 6.7.2p2: "At least one type specifier shall
    > be given in the declaration specifiers in each declaration,
    > and in the specifier-qualifier list in each struct declaration and type
    > name." Therefore a diagnostic is required.


    I don't think he's talking about implicit int. I certainly wasn't.

    However, I still think it's a constraint violation. I think 6.5.1 p2
    and 6.5.2.2 p1 conspire to make it so (either on it's is probably
    enough).

    --
    Ben.
     
    Ben Bacarisse, Feb 14, 2012
    #10
  11. /dev/phaeton

    James Kuyper Guest

    On 02/14/2012 05:35 PM, Ben Bacarisse wrote:
    > James Kuyper <> writes:
    >
    >> On 02/14/2012 04:47 PM, Peter Nilsson wrote:
    >>> Ben Bacarisse <> wrote:
    >>>> In C99 implicit declarations are not permitted.
    >>>
    >>> They're no longer required, but if a C99+ implementation
    >>> decides to support them anyway, no diagnostic is required
    >>> for their use.

    >>
    >> Its a constraint violation - 6.7.2p2: "At least one type specifier shall
    >> be given in the declaration specifiers in each declaration,
    >> and in the specifier-qualifier list in each struct declaration and type
    >> name." Therefore a diagnostic is required.

    >
    > I don't think he's talking about implicit int. I certainly wasn't.


    Calling a function without a declaration in scope is a constraint
    violation (6.5.2.2p2). If an actual declaration is present, an implied
    one is unnecessary (except when the implicit int rule was in effect,
    which it no longer is). So if an implicit declaration is needed, there's
    either a constraint violation in the declaration of the function or in
    the call of the function.

    > However, I still think it's a constraint violation. I think 6.5.1 p2
    > and 6.5.2.2 p1 conspire to make it so (either on it's is probably
    > enough).


    6.5.2.2p1 is the one that seems relevant to me.
     
    James Kuyper, Feb 14, 2012
    #11
  12. James Kuyper <> writes:

    > On 02/14/2012 05:35 PM, Ben Bacarisse wrote:
    >> James Kuyper <> writes:
    >>
    >>> On 02/14/2012 04:47 PM, Peter Nilsson wrote:
    >>>> Ben Bacarisse <> wrote:
    >>>>> In C99 implicit declarations are not permitted.
    >>>>
    >>>> They're no longer required, but if a C99+ implementation
    >>>> decides to support them anyway, no diagnostic is required
    >>>> for their use.
    >>>
    >>> Its a constraint violation - 6.7.2p2: "At least one type specifier shall
    >>> be given in the declaration specifiers in each declaration,
    >>> and in the specifier-qualifier list in each struct declaration and type
    >>> name." Therefore a diagnostic is required.

    >>
    >> I don't think he's talking about implicit int. I certainly wasn't.

    >
    > Calling a function without a declaration in scope is a constraint
    > violation (6.5.2.2p2).


    Did you mean p2? p2 is entirely conditional and it might not apply.

    > If an actual declaration is present, an implied
    > one is unnecessary (except when the implicit int rule was in effect,
    > which it no longer is). So if an implicit declaration is needed, there's
    > either a constraint violation in the declaration of the function or in
    > the call of the function.


    I am sure we agree, but I don't find your reasoning easy to follow. In
    addition to text that defines a constraint, there must also be an
    absence on any text that permits implicit declarations. C90 has almost
    exactly the same wording as C99's 6.5.2.2 p1 (and p2 for that matter)
    yet C99 and C90 differ in this regard. This is because C90 has wording
    (that C99 does not) that defines an explicit declaration in certain
    cases.

    My point is you can't just say "because of 6.5.2.2p2". Of course, I
    also made this mistake by just citing two sections. I should also have
    said "and there's nothing that says a declaration will be assumed".

    >> However, I still think it's a constraint violation. I think 6.5.1 p2
    >> and 6.5.2.2 p1 conspire to make it so (either on it's is probably
    >> enough).

    >
    > 6.5.2.2p1 is the one that seems relevant to me.


    I am not sure it has much relevance (see below) but in any case it can't
    rule out all cases on it's own. What's wrong with this:

    void (*fp)(void) = function;

    in the absence of a declaration for 'function'? 6.5.2.2 p1 does not
    prohibit it, but 6.5.1 p2 does. As you can see, I'm retracting my view
    that either one is probably enough. I think 6.5.1 p2 is probably enough
    on it's own because it says that both the above and

    function();

    are constraint violations when there's no function declaration in scope.
    6.5.2.2 p1 rules out things like this:

    int f;
    f();

    but when f has no declaration at all, f() is not even a function call
    expression.

    --
    Ben.
     
    Ben Bacarisse, Feb 15, 2012
    #12
  13. James Kuyper <> wrote:
    > Peter Nilsson wrote:
    > > Ben Bacarisse <> wrote:
    > > > In C99 implicit declarations are not permitted.

    > >
    > > They're no longer required, but if a C99+ implementation
    > > decides to support them anyway, no diagnostic is required
    > > for their use.

    >
    > Its a constraint violation - 6.7.2p2: "At least one type specifier shall
    > be given in the declaration specifiers in each declaration,
    > and in the specifier-qualifier list in each struct declaration and type
    > name." Therefore a diagnostic is required.


    My bad. I was looking at using functions without a declaration in
    scope.
    e.g...

    #include <stdio.h>
    int main(void) { foo(); return 0; }
    int foo(void) { puts("42"); return 0; }

    AFAICS, if a C99+ implementation supports C90 style implicit function
    declarations as an extension, then it is not required to issues a
    diagnostic since no constraint would be violated.

    --
    Peter
     
    Peter Nilsson, Feb 15, 2012
    #13
  14. /dev/phaeton

    /dev/phaeton Guest

    On 02/14/2012 03:09 AM, Kaz Kylheku wrote:

    > With what warning options?
    >
    > How about with -Wall and -W?


    Honestly? None. I suppose I should start using them.


    However, the gist that I'm getting from all this...

    It's a good idea to do prototyping, and in the worst case scenario it is
    just superfluous. So I will continue to do them.

    Sorry to start a lukewarm debate- though it's been quite educational for
    me to read through it. I thank you all for that.


    Stephen Sprunk wrote:

    >> In K&R2, function definitions in a program were preceded by a function
    >> prototype, i.e.:


    >> int my_function(int variable1, int variable2);


    > Note this is a prototyped function _declaration_.


    I will have to re-read the K&R2 usage of "definition" and "declaration".
    I seem to be confused on which is which. Thanks for the correction.

    Out of time for now... Back to A&P II homework for the rest of the
    night. *sigh*

    -J
     
    /dev/phaeton, Feb 15, 2012
    #14
  15. Peter Nilsson <> writes:
    [...]
    > My bad. I was looking at using functions without a declaration in
    > scope.
    > e.g...
    >
    > #include <stdio.h>
    > int main(void) { foo(); return 0; }
    > int foo(void) { puts("42"); return 0; }
    >
    > AFAICS, if a C99+ implementation supports C90 style implicit function
    > declarations as an extension, then it is not required to issues a
    > diagnostic since no constraint would be violated.


    No, that's still a constraint violation (strictly speaking a syntax
    error), and providing an extension doesn't permit a compiler to
    omit the required diagnostic.

    C99 6.5.1p2:

    An identifier is a primary expression, provided it has been
    declared as designating an object (in which case it is an lvalue)
    or a function (in which case it is a function designator).

    with a footnote:

    Thus, an undeclared identifier is a violation of the syntax.

    A conforming C99+ compiler may support this as an extension, but
    it still has to issue a diagnostic.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Feb 15, 2012
    #15
  16. /dev/phaeton

    Kaz Kylheku Guest

    On 2012-02-15, /dev/phaeton <blahbleh666@no_more_spam.hotmail.com> wrote:
    > On 02/14/2012 03:09 AM, Kaz Kylheku wrote:
    >
    >> With what warning options?
    >>
    >> How about with -Wall and -W?

    >
    > Honestly? None. I suppose I should start using them.
    >
    >
    > However, the gist that I'm getting from all this...
    >
    > It's a good idea to do prototyping, and in the worst case scenario it is
    > just superfluous. So I will continue to do them.


    Or instead of duplicating every declaration, you could just turn on the right
    diagnosticxs in the compiler so that you're told when a prototype is necessary,
    but missing.

    Writing declarations just for the sake of writing declarations can even
    lead you to a mistake.

    /* forgot to include "foo.h" where foo is declared */

    int foo(char *x)
    {
    }

    If you use -Wstrict-prototypes -Wmissing-prototypes, GCC can help you
    catch the problem that a declaration was forgotten.

    This could indicate that the header file was not included, meaning
    that the program is at risk of being inconsistent (definition changes
    but the header file declaration does not).

    Sometimes this diagnostic indicates that a function which should be static has
    been made external.

    But if you have a declaration like in the above, then this diagnostic is shut
    up:

    /* forgot to include "foo.h" where foo is declared */

    int foo(char *x);

    /*...*/

    int foo(char *x)
    {
    }

    The issue is that "foo.h" could have the wrong prototype, causing other
    translation units to have incorrect calls to foo.
     
    Kaz Kylheku, Feb 15, 2012
    #16
  17. /dev/phaeton

    James Kuyper Guest

    On 02/15/2012 12:51 AM, /dev/phaeton wrote:
    > On 02/14/2012 03:09 AM, Kaz Kylheku wrote:
    >
    >> With what warning options?
    >>
    >> How about with -Wall and -W?

    >
    > Honestly? None. I suppose I should start using them.
    >
    >
    > However, the gist that I'm getting from all this...
    >
    > It's a good idea to do prototyping, and in the worst case scenario it is
    > just superfluous.


    Keep in mind that your original question, whatever you might have
    thought to the contrary, was not actually about whether prototyping
    should be done, but about whether it should be done twice - once in a
    function declaration, and a second time in the function definition. The
    separate declaration often is, as you say, superfluous, and should not
    be used if that is the case.

    Whether you need to provide a separate declaration is just a matter of
    how you organize your code, but you should always use a prototype
    whenever you either declare or define a function. They're extremely
    useful - they're never superfluous. That's primarily because they allow
    the C implementation to recognize certain common kinds of mistakes, and
    require it to give you a diagnostic message if you've made one of those
    mistakes.

    On the separate declaration issue:
    The first part of a function's definition is, in itself, a declaration
    of the function, so if you never use a function anywhere but in a single
    file, and if you define that function prior to any calls to that
    function, a separate declaration of the function unnecessarily
    complicates your code, and should not be provided. The only case where
    this doesn't work is mutually recursive functions - for instance, if
    func1() calls func2(), and func2() also calls func1(), at least one of
    them must be declared first, with the definition coming later.

    For any function which is used in at least one file other than the one
    in which it is defined, you should create a header file containing a
    declaration of that function, and #include that header file in any file
    where that function is used. You should also #include that header file
    in the file where the function is defined - that way, if you made a
    mistake and the declaration of the function isn't compatible with the
    definition of the function, you'll get a diagnostic message telling you so.
    --
    James Kuyper
     
    James Kuyper, Feb 15, 2012
    #17
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Sims
    Replies:
    8
    Views:
    321
    Victor Bazarov
    Aug 8, 2003
  2. Michele Simionato
    Replies:
    12
    Views:
    508
    Jonathan Gardner
    May 7, 2004
  3. vlsidesign
    Replies:
    26
    Views:
    997
    Keith Thompson
    Jan 2, 2007
  4. SM
    Replies:
    9
    Views:
    510
  5. Syren Baran

    function prototypes and function addresses

    Syren Baran, Jan 9, 2008, in forum: C Programming
    Replies:
    6
    Views:
    310
Loading...

Share This Page