What is K&R style function definition in C?

Normally you see function definitions like:

int foo(char* s, float f, struct Baz * b) {
  return 5;
}

This describes the parameters of the function foo: how many there are, and what their types are. It does so using a parameter type list, but there’s another way to do it: an initializer list.

int foo(s, f, b)
  char* s;
  float f;
  struct Baz * b;
{
  return 5;
}

In this style, we write the types of the parameters immediately before the block. This is not just a syntactic difference! The semantic difference is significant: it produces a function declaration which says nothing about the parameters. So the corresponding declaration is:

int foo();

Such a declaration means: “this function has an unknown number of parameters, of unknown types”. (It does not mean that the function has no parameters!)

Calls to foo are checked against its declaration, not its definition. This means the compiler will accept any list of arguments at all, easily leading to undefined behavior. We should not use this style.

This would be an obscure relic of C if it were not for the following function definition. Which style does it use?

int foo() {
  return 5;
}

It could be either, right? Wrong! It uses an initializer list - the old style! To use a parameter type list, we must write:

int foo(void) {
  return 5;
}

The “initializer list” style is also called “K&R-style”, as opposed to “ANSI-style”. K&R-style has no advantages, but compilers will accept it anyway - even clang -pedantic issues no warnings.

I wrote this because I felt like it. This post is not associated with my employer.