To be truly standards-compliant, must all functions in C (except for main) have a prototype, even if they are only used after their definition in the same translation unit?
-
1The question [Must declare function prototype in C?](http://stackoverflow.com/questions/2575153/must-declare-function-prototype-in-c) was once proposed as a duplicate of this on. There would have to be a strong reason to close an older question as a duplicate of a newer one rather than vice versa. – Jonathan Leffler Aug 24 '15 at 14:08
6 Answers
It depends on what you mean by 'truly standards compliant'. However, the short answer is "it is a good idea to ensure that all functions have a prototype in scope before being used".
A more qualified answer notes that if the function accepts variable arguments (notably the printf()
family of functions), then a prototype must be in scope to be strictly standards compliant. This is true of C89 (from ANSI) and C90 (from ISO; the same as C89 except for the section numbering). Other than 'varargs' functions, though, functions which return an int
do not have to be declared, and functions that return something other than an int
do need a declaration that shows the return type but do not need the prototype for the argument list.
Note, however, that if the function takes arguments that are subject to 'normal promotions' in the absence of prototypes (for example, a function that takes a char
or short
- both of which are converted to int
; more seriously, perhaps, a function that takes a float
instead of a double
), then a prototype is needed. The standard was lax about this to allow old C code to compile under standard conformant compilers; older code was not written to worry about ensuring that functions were declared before use - and by definition, older code did not use prototypes since they did not become available in C until there was a standard.
C99 disallows 'implicit int'...that means both oddball cases like 'static a;
' (an int
by default) and also implicit function declarations. These are mentioned (along with about 50 other major changes) in the foreword to ISO/IEC 9899:1999,
which compares that standard to the previous versions:
- remove implicit
int
…- remove implicit function declaration
In ISO/IEC 9899:1990, §6.3.2.2 Function calls stated:
If the expression that precedes the parenthesized argument list in a function call consists solely of an identifier, and if no declaration is visible for this identifier, the identifier is implicitly declared exactly as if, in the innermost block containing the function call, the declaration:
extern int identifier();
appeared.38
38 That is, an identifier with block scope declared to have external linkage with type function without parameter information and returning an
int
. If in fact it is not defined as having type “function returningint
,” the behavior is undefined.
This paragraph is missing in the 1999 standard. I've not (yet) tracked the change in verbiage that allows static a;
in C90 and disallows it (requiring static int a;
) in C99.
Note that if a function is static, it may be defined before it is used, and need not be preceded by a declaration. GCC can be persuaded to witter if a non-static function is defined without a declaration preceding it (-Wmissing-prototypes
).

- 5,271
- 9
- 40
- 61

- 730,956
- 141
- 904
- 1,278
-
3Points for humorous use of "witter" (to speak at length on a trivial subject.) I'd subtract for the common misuse of "verbiage" (excessive wordiness) to mean "language", but after considering the text of the C standards, I decided to take it as more subtle and very on-target humor. – Jeff Learman Aug 03 '18 at 18:47
A prototype is a function declaration that specifies the types of the function's parameters.
Pre-ANSI C (the language described by the 1978 first edition of Kernighan & Ritchie's "The C Programming Language") did not have prototypes; it was not possible for a function declaration to describe the number or types of the parameters. It was up to the caller to pass the correct number and type of arguments.
ANSI C introduced "prototypes", declarations that specify the types of the parameters (a feature borrowed from early C++).
As of C89/C90 (the ANSI and ISO standards describe the same language), it's legal to call a function with no visible declaration; an implicit declaration is provided. If the implicit declaration is incompatible with the actual definition (say, calling sqrt("foo")
, then the behavior is undefined. Neither this implicit declaration nor a non-prototype declaration can be compatible with a variadic function, so any call to a variadic function (like printf
or scanf
) must have a visible prototype.
C99 dropped implicit declarations. Any call to a function without a visible declaration is a constraint violation, requiring a compiler diagnostic. But that declaration is still not required to be a prototype; it can be an old-style declaration that doesn't specify parameter types.
C11 made no significant changes in this area.
So even as of the 2011 ISO C standard, old-style function declarations and definitions (which have been "obsolescent" since 1989) are still permitted in conforming code.
For all versions of C going back to 1989, as a matter of style, there is very little reason not to use prototypes for all functions. Old-style declarations and definitions are kept only to avoid breaking old code.

- 254,901
- 44
- 429
- 631
-
Certain semantics can be achieved using old-style declarations which would not be achievable using prototypes. For example, a function which sometimes makes use of its parameters may be legitimately be called with no arguments if it will know [perhaps on the basis of a global or static variable] that it shouldn't examine any of its parameters. If an API requires such abilities, it may not be possible to code it using new-style prototypes. – supercat Dec 25 '16 at 21:21
-
2@supercat: Incorrect. If a non-variadic function's *definition* declares, say, 2 parameters, then a call that doesn't pass exactly 2 arguments of the appropriate type(s) has undefined behavior. Using a non-prototype declaration just prevents the compiler from diagnosing the error. – Keith Thompson Dec 25 '16 at 21:46
-
Whether or not implementations are *required* to allow callers to pass varying amounts of arguments to functions which aren't explicitly declared variadic, there certainly existed implementations which documented behavior in such cases, as well as APIs that exploit it. For example, a loadable library which uses one entry point for many functions, and uses the first argument to select the function to be invoked. The C Standard says nothing about how loadable libraries should work, but if an implementation for a platform supported loadable libraries using such a model... – supercat Dec 25 '16 at 22:49
-
1...in the days before the Standard, any future implementations for that platform which were required to support that pre-existing code would be compelled to support variadic calls whether or not the Standard would require them. – supercat Dec 25 '16 at 22:52
-
1The standard quite explicitly **does not support** what you're talking about. [N1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 6.5.2.2 paragraph 6: "If the number of arguments does not equal the number of parameters, the behavior is undefined." The pre-existing code you're talking about is exactly why `
` and explicit variadic functions were introduced. One example of what you're talking about is the POSIX `open()` function, which traditionally takes 2 or 3 arguments; POSIX specifies it as a variadic function. The question is about C89/C90 and C99, not pre-ANSI C. – Keith Thompson Dec 25 '16 at 22:55 -
RItchie's 1974 compiler defined behavior of variadic functions, as did many other compilers throughout the next 15 years, without any requirement that the declarations or definitions specify that the functions were variadic. While such behavior may not have been supported by all pre-Standard implementations, I've seen no indication that the Standard was supposed to discourage compilers from continuing to support such semantics on platforms where they had been supported previously. – supercat Dec 25 '16 at 23:02
-
2If you're going to advocate horrendously non-portable practices like this, at least make it very clear that they're non-portable, and that you're making assumptions based on a 42-year-old document that has been superseded multiple times. Passing the wrong number of arguments to a function is not portable, **and is not common practice**. – Keith Thompson Dec 25 '16 at 23:05
-
I wouldn't recommend that someone developing an API require the use of such techniques, but the systems I've seen through the years which document their calling conventions have consistently defaulted to calling conventions which are robust to excess arguments or the omission of unused arguments. The Standard would allow for implementations to use other conventions where that wouldn't work, and some systems I've used have options to employ such conventions, but I don't think that would qualify them as "horrendously non-portable compared with code that assumes.. – supercat Dec 26 '16 at 05:11
-
...that it's safe to multiply 1000 by 1000 without using a suffix on either value. – supercat Dec 26 '16 at 05:12
-
-
do you know of any platform or C11 implementation where an otherwise valid call to `printf()` fails due to a missing prototype? In other words, what does "must have a visible prototype" mean? (`int main(void){int i = 1; printf("%d", i); }`) – jfs Oct 22 '17 at 16:05
-
is it all? If you do not convert a compiler warning into an error then are there any other effects? – jfs Oct 22 '17 at 19:07
-
@jfs: Maybe? As far as C is concerned, it's a constraint violation, requiring a diagnostic. The C standard doesn't care whether the diagnostic is a non-fatal warning or a fatal error message. Other than the required handling of the `#error` directive, that's as close as the C standard gets to saying something is illegal. If a compiler doesn't reject the program, its behavior is not defined by the standard. Your question is about the behavior of a particular compiler. If you're curious, you might post a new question (though the best advice is simply "Don't do that.") – Keith Thompson Oct 24 '17 at 00:10
-
If you have a *declaration* that isn't a prototype, like `int printf();`, the behavior is undefined but no diagnostic is required. So don't do that either. – Keith Thompson Oct 24 '17 at 00:11
No, functions do not always need a prototype. The only requirement is that a function be "declared" before you use it. There are two ways to declare a function: to write a prototype, or to write the function itself (called a "definition.") A definition is always a declaration, but not all declarations are definitions.

- 48,337
- 13
- 89
- 105
-
13In C99, you're correct. In C89/C90, you did not need to pre-declare a function; it would be implicitly declared as function taking undefined list of arguments and returning int simply by being used as a function. – Jonathan Leffler Jan 13 '09 at 14:31
-
5This distinction between C99 and pre-C99 standards can be significant, as evidenced in this comp.lang.c FAQ question: http://c-faq.com/malloc/mallocnocast.html – nagul Aug 05 '09 at 10:18
-
Good answer, though you might note that some compilers which encountered a call to an undeclared function would assume it was an `int` function whose arguments precisely matched what was passed in the call, assuming standard promotions. Such compilers would generally give an error if a declaration was found in the same compilation unit which would contradict the one that was inferred. If no declaration was found, and the argument types weren't guessed correctly (compared with a separately-compiled function definition), the problem may or may not be detected at link time. – supercat Jun 11 '12 at 15:30
-
1A declaration "int foo();" is not a prototype, but would suffice to allow code to call "foo" with any number of parameters, provided that "foo" is defined, somewhere, using the "old" style, and provided that it never tries to use more arguments than are passed to it. – supercat Dec 25 '16 at 21:22
-
@supercat: Sorry I didn't respond to this comment earlier. This is incorrect. If `foo` is called with parameters inconsistent with its definition, the behavior is undefined. For example, if `foo` is defined with 2 `int` parameters, calling it with 3 `foo` parameters has undefined behavior. Whatever you're trying to do with this non-portable hack, there's a better and more portable way to do it. – Keith Thompson Jul 11 '19 at 21:46
-
@KeithThompson: The most commonly used calling conventions when the Standard was written were explicitly designed to allow such usage. Prior to C becoming popular, the normal calling conventions on both the Macintosh and PC platforms didn't allow such usage, but people designing C compilers for those platforms opted to use calling conventions that could support it rather than using the platforms' normal conventions. The Standard doesn't *require* that implementations support such usage, but people writing Mac and PC compilers seemed to think quality implementations should do so anyway. – supercat Jul 11 '19 at 22:17
A nice tip when writing new functions is to write them upside-down with main at the bottom so when you change your mind about the function's args or return type you don't have to fix the prototype too. Constantly fixing prototypes, and dealing with all the compiler's warnings when they are out of date gets really tedious.
Once you have your functions working smoothly together move the code to a well-named module and put the prototypes in a .h file of the same name. It saves serious time. The biggest productivity aid I've found in 5 years.
Yes, every function must have a prototype, but that prototype may appear either in a separate declaration or as part of the function's definition. Function definitions written in C89 and up naturally have prototypes, but if you write things in classic K&R style, thus:
main (argc, argv)
int argc;
char **argv;
{
...
}
then the function definition has no prototype. If you write ANSI C (C89) style, thus:
main (int argc, char **argv) { ... }
then the function definition has a prototype.

- 198,648
- 61
- 360
- 533
-
2K&R function definitions are still legal in C89 (although not recommended) , so the statement "every function must have a prototype" is not true. – M.M Aug 28 '15 at 00:30
-
This answer contradicts itself, but it's useful in presenting the K&R C style of defining function arguments in the function definition. One hopes never to see such code any more, but sometimes we do have to do some code-archeology! – Jeff Learman Aug 03 '18 at 18:56
-
1
-
@KeithThompson True, and that significantly detracts from its usefulness. I would have up-voted it, otherwise. – Jeff Learman Aug 03 '18 at 19:45
To the best of my knowledge (in ANSI C89/ISO C90), no. I am unsure about C99; however, I would expect the same.
Personal Note: I only write function prototypes when...
- I need to (when A() calls B() and B() calls A()), or
- I am exporting the function; otherwise, it feels superfluous.
-
A prototype is a function declaration that specifies the types of the parameters. I needn't be a separate declaration; it can be part of the function definition. For example, this definition: `void func(int n) { /* ... */ }` includes a prototype. – Keith Thompson Apr 26 '17 at 17:06
-
@KeithThompson Right, but I assume he meant "I only write separate function prototypes when ..." This is pretty common practice. It's also a good practice to make all functions static unless we prototype them in a header file. Thank goodness for the compiler warning for calling functions without prototypes! That mitigated the most common cause of errors in C code, as those of us who coded back in the 80's well know. – Jeff Learman Aug 03 '18 at 19:02
-
@JeffLearman I dislike making implicit assumptions about what people mean. You're interpretation is likely correct, but the wording is also consistent with using old-style declarations and definitions in most cases, and using prototypes in the cases listed. – Keith Thompson Aug 03 '18 at 19:17