Are prototypes required for all functions in C89, C90 or C99?
Asked Answered
M

6

55

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?

Miniaturize answered 12/1, 2009 at 8:9 Comment(1)
The question 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.Obryant
O
43

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 returning int,” 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).

Obryant answered 13/1, 2009 at 2:16 Comment(1)
Points 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.Desired
G
21

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.

Genus answered 23/8, 2013 at 22:33 Comment(14)
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.Pentose
@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.Genus
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...Pentose
...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.Pentose
The standard quite explicitly does not support what you're talking about. N1570 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 <stdarg.h> 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.Genus
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.Pentose
If 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.Genus
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..Pentose
...that it's safe to multiply 1000 by 1000 without using a suffix on either value.Pentose
Comments are meant to clarify. This is an irrelevant tangent.Genus
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); })Scarface
is it all? If you do not convert a compiler warning into an error then are there any other effects?Scarface
@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.")Genus
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.Genus
P
15

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.

Pyelography answered 12/1, 2009 at 8:39 Comment(6)
In 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.Obryant
This distinction between C99 and pre-C99 standards can be significant, as evidenced in this comp.lang.c FAQ question: c-faq.com/malloc/mallocnocast.htmlMarek
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.Pentose
A 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.Pentose
@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.Genus
@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.Pentose
W
3

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.

Whangee answered 6/9, 2015 at 10:20 Comment(0)
M
1

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.

Morganica answered 13/1, 2009 at 2:0 Comment(4)
K&R function definitions are still legal in C89 (although not recommended) , so the statement "every function must have a prototype" is not true.Organization
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!Desired
@JeffLearman: It may be useful, but it's factually incorrect.Genus
@KeithThompson True, and that significantly detracts from its usefulness. I would have up-voted it, otherwise.Desired
D
0

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...

  1. I need to (when A() calls B() and B() calls A()), or
  2. I am exporting the function; otherwise, it feels superfluous.
Dichy answered 12/1, 2009 at 8:9 Comment(3)
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.Genus
@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.Desired
@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.Genus

© 2022 - 2024 — McMap. All rights reserved.