Talk:Function prototype

Rewrite/Check example

edit

I just rewrote this page, and expanded it by a decent amount. I was considering removing the stub status, but I think that this page is in a grey area right now. Plus, I'm new here and I thought it better to leave such judgements to the more experienced Wikipedians.

One thing that should definitely be checked is the accuracy of the example in the "informing the compiler" section. The only C compiler I've used is gcc, so I don't know if other compilers behave in the same way. --seliopou 02:08, 4 Apr 2005 (UTC)

I don't think the example is really good. The compiler will always catch an error wherever the function is declared, with or without a prototype. It's like this:
int fac(int n) {             /* Called function  */
    if (n == 0) {
        return 1;
    }
    else {
        return n * fac(n - 1);
    }
}
int main() {                 /* Calling function */
    printf("%d\n", fac());   /* ERROR: fac is missing an argument! */
    return 0;
}
This will result in two errors - called from main, no matching function fac(void), candidate is fac(int); called from fac, fac(int) not declared.
While the other way round, an error will still be catched
int main() {                 /* Calling function */
    printf("%d\n", fac());   /* ERROR: fac is missing an argument! */
    return 0;
}
int fac(int n) {             /* Called function  */
    if (n == 0) {
        return 1;
    }
    else {
        return n * fac(n - 1);
    }
}
The compiler error message will say: from main, fac() not declared. So the whole thing is not a good example at all. It could be better if an argument is given to fac, making it say fac(10). --Deryck C. 02:32, 12 March 2007 (UTC)Reply

Agree to Deryck. The example does not look brilliant as the result in compiler-dependent. Probably, a better example to explain the need for prototypes in something like:

int functionA(int n);
int functionB(int n);

int main()
{
    int n, res;
    /* do smth with n */
    res = functionA(n);
    return res;
}

int functionA(int n)
{
    /* do smth with n */
    if (/* some logic */)
    {
        n = functionB(n);
    }
    return n;
}

int functionB(int n)
{
    /* do smth with n */
    if (/* some logic */)
    {
        n = functionA(n);
    }
    return n;
}

- a very rough example, the idea behind is that both functionA and functionB recursively call each other in some circumstances (plus main calls functionA). Therefore, it's nice to have prototype declarations (at least, from codestyle point of view, even despite ingenious compiler you might have :). Rainor (talk) 08:59, 28 October 2008 (UTC)Reply

Article is misleading

edit

The article was misleading - it sounded like any function declaration is a prototype. I tried to clear up matters. Please check whether it is clearer now, and mark places that need discussion and/or citation.

I checked my changes against the C99 TC3 draft.

Then provide paragraph numbers and cite it - making unsourced edits and demanding that other people provide the citations isn't expected Tedickey (talk) 00:35, 28 August 2009 (UTC)Reply
Not specific to C99, here is a discussion of "unspecified" versus "undefined" (there might be a copy of the corresponding text for C99 online; you're welcome to provide that source for discussion) Tedickey (talk) 00:44, 28 August 2009 (UTC)Reply
Ok, i think you want a citation of my edit where i changed "unspecified" to "undefined.". I didn't know that one has to provide source-links, sorry i will do that in future on the discussion page. Here it goes: Paragraph 6.5.2.2/6 explicitly says that:

If the expression that denotes the called function has a type that does not include a prototype,.... If the number of arguments does not equal the number of parameters, the behavior is undefined. If the function is defined with a type that includes a prototype, and either the prototype ends with an ellipsis (, ...) or the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined.

Because behavior is undefined, we can't know whether the compiler won't complain. If the definition appears in the same translation unit, it's well possible that a good compiler complains about the incompatible argument types. Of course, if the expression denoting the function has a type that includes a prototype (declares the parameter types), then behavior is not undefined, and a diagnostic is required because the following rule appears as a constraint:

If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.

That's why i changed the text to "behavior may be undefined" (it is undefined if the prototype declaration is commented out). Furthermore, a prototype can be contained in a defining declaration too. A prototype is the declaration of a function that includes the type of its parameters. A definition with a suitable parameter-type-list satisfies that all the way. That's why i removed the part in the introduction (see 6.2.1/2 for a citation of that).
As a last comment, i'm sorry for my poor english. Feel free to improve my wording. Litb me (talk) 00:50, 28 August 2009 (UTC)Reply
I prefer the C rationale document, which explains things (undefined and unspecified behavior is also explained in the draft - but the description is rather short. The rationale document is much more elaborate): http://www.lysator.liu.se/c/rat/a.html#1-6 . A C99 version is available as a PDF document: http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf . It also explains that implicit function declarations don't exist in C99 anymore:

A new feature of C99: The rule for implicit declaration of functions has been removed in C99. The effect is to guarantee the production of a diagnostic that will catch an additional category of programming errors. After issuing the diagnostic, an implementation may choose to assume an implicit declaration and continue translation in order to support existing programs that exploited this feature.

—Preceding unsigned comment added by Litb me (talkcontribs) 01:11, 28 August 2009 (UTC)Reply
I haven't TC3 at hand, but do have ISO/IEC 9899:1999 pdf. The wording is similar. However, the point of the "int foo(int)" is that omitting the prototype, the effect is almost the same since the type of the return-value is int, and the parameter(s) are also int (default promotion). So the case never gets into the clause about undefined behavior; 6.5.2.2/6 still blesses that. Tedickey (talk) 01:06, 28 August 2009 (UTC)Reply
If the prototype were "char *foo(double bar)", then omitting that would result in undefined behavior. Tedickey (talk) 01:08, 28 August 2009 (UTC)Reply
The implicit declaration has no parameter type list: The type of any argument that triggers an implicit declaration does not influence the function type of that declaration. The argument, however, will be of type int if you were to pass any argument that will be default-promoted to int. But you don't pass any argument at all. In main, you call the function with zero arguments - which is the point where the undefined behavior happens :) Litb me (talk) 01:15, 28 August 2009 (UTC)Reply
I see that in the rationale (page 103, lines 33-35). For the standard itself, it is not so clear. Tedickey (talk) 09:34, 28 August 2009 (UTC)Reply


But do you agree with me that you have overseen that in main the function is called *without arguments*? You assumed that the function is called with "parameter(s) [that] are also int". Of course, this yields to undefined behavior then. I should have been clearer with "The type of any argument that triggers an implicit declaration does not influence the function type". What i meant was "The type of any argument in a call that triggers an implicit declaration of the function does not influence the function type...". In any case, what you refer to (line 33-35) doesn't have anything to do with this all. It is similar to the "implicit int" rule, and refers to this situation:
void f(a) {
  /* a is implicitly assumed to 
   * have type int, because it's 
   * not declared */
}
In C99, such an old-style definition has to give a declaration for "a". In any case, "a" is a parameter, not an argument. Finally, what is your position on whether or not you agree with changing the wording to "undefined" and removing the introductory mentioning of "that omits a body"? (prototypes can appear in function *definitions* too). 84.174.237.26 (talk) 17:50, 28 August 2009 (UTC)Reply
Regarding "undefined": The rationale refers to "constraint violation" (not "undefined"), to produce a "diagnostic". That doesn't appear to agree with "undefined". See page 18 (of the rationale), lines 23-29. The rationale prescribes behavior for this case; it is well-defined. (Bear in mind that the rationale is not the standard - perhaps the terse "remove implicit function declaration" on page 12 in the Foreward is standardese for the feature we're discussing, but it would be nice to point to something more substantial than that in the standard). Tedickey (talk) 00:41, 29 August 2009 (UTC)Reply
I'm sorry i don't know what you refer to or what you want to clarify about "undefined". Please use section and paragraph numbers when referring to places in the rationale or standard. Regarding the changes i want to make: I gave section and paragraph numbers to the Standard. "Undefined behavior" is a violation of a "shall" that does not appear in a constraint, or behavior that is not explicitly specified or behavior that's explicitly specified as being undefined. In our case, the behavior is explicitly specified as being undefined. I assumed you know what it is before asking me that i should inform myself on the difference of it and unspecified behavior. Litb me (talk) 00:56, 30 August 2009 (UTC)Reply
The rationale says that a diagnostic would be given, and that implementations are allowed to support the legacy feature. That matches the category on page 18 of the rationale for unspecified, rather than undefined. My comment to which you responded is that the standard itself does not appear to support the statement in the rationale, and suggesting that you might see some corresponding wording (in the standard itself) to tie things together. Tedickey (talk) 08:42, 31 August 2009 (UTC)Reply
I haven't seen where in the rationale it says that a diagnostic would be given for the call to "fac()" (notice the zero arguments) in main. Please give a section and paragraph number for that. Also note that in case a violation within a constraint is explicitly specified as being undefined, a diagnostic must be given in addition, even though behavior is still undefined. (that's specified in 5.1.1.3/1 in the standard C99 TC3 draft). Also note that undefined behavior also allows supporting features whatever the implementation likes. Undefined behavior in fact allows doing *anything*. In any case, i would like to ask to move away from the rationale to the Standard. I gave section and paragraph numbers for my edit at the very beginning (6.5.2.2/6). If you can't find anything that says that paragraph doesn't state it's undefined behavior (and i, of course, very much doubt that), i will revert to my change of the article. Litb me (talk) 02:59, 1 September 2009 (UTC)Reply
Wait, i think i know now where you refer to. Do you refer to my quote of the rationale? Well, that was *only* about implicit declarations. If you were to provide a declaration of "fac" without a prototype like "void fac();", then there is no diagnostic required, because there *is* a declaration in scope then. But behavior is still undefined when fac is called with zero arguments (6.5.2.2/6) Also note that behavior is not magically "unspecified" my merely saying that a diagnostic is given. A diagnostic is given for any violation of a constraint or any syntax rule. Also note that the whole code assumed C89 (not C99), and in C89 an implicit declaration would declare the function without using a prototype and would not require a diagnostic. Litb me (talk) 03:14, 1 September 2009 (UTC)Reply
yes, I was referring to the rationale, page 69 lines 23-27 which you quoted, as well as page 103 lines 33-38. The current point of disagreement seems to be whether the behavior is "undefined" or "unspecified". (Noting that you're referencing TC3, ISO/IEC 9800:1999 does not contain either term). Thinking over that, I suppose there's more support for "undefined", since it states that the latitude associated with "unspecified" "does not extend as far as failing to translate the program". Tedickey (talk) 08:28, 1 September 2009 (UTC)Reply
What i referenced of course contains the term "undefined": "...If the number of arguments does not equal the number of parameters, the behavior is undefined...". I showed it at the very start of the discussion :) Please don't give page and line numbers, they are ambiguous because their logical page numbers (printed on the bottom) differ from the physical page numbers of the PDF document and line numbers don't make clear whether to count whitespace lines etc - section and paragraph numbers are unambiguous. Regarding to p103, line 33 (assuming physical page number), i explained how that doesn't relate to our discussion (the code sample i gave "void f(a) { }". Page 69 line 23 also only refers to implicit declarations, which wasn't what we were discussing either - i only brought it into discussion to judge my insertion of "prior to C99" at the Start of the paragraph in the article. The paragraphs that are relevant to "unspecified -> undefined" were quoted by me out of the standard at the very start of the discussion. But i'm glad to see that we seem to come to an agreement finally :) Litb me (talk) 16:25, 1 September 2009 (UTC)Reply
sounds okay Tedickey (talk) 21:08, 1 September 2009 (UTC)Reply

Very basic concept should not confuse the reader

edit

This is such a basic concept that any reader looking here should not be confused with internal details like "on the stack (possibly a return address ..." and scope.

Keeping the example to the minimum is of paramount importance. adding a recursive call is really way out there.

The article should not leave the reader with more questions.

DGerman (talk) 20:36, 24 November 2021 (UTC)Reply