1

In C when a function is declared like void main(); trying to input an argument to it(as the first and the only argument) doesn't cause a compilation error and in order to prevent it, function can be declared like void main(void);. By the way, I think this also applies to Objective C and not to C++. With Objective C I am referring to the functions outside classes. Why is this? Thanks for reaching out. I imagine it's something like that in Fortran variables whose names start with i, j, k, l, m or n are implicitly of integer type(unless you add an implicit none).

Edit: Does Objective C allow this because of greater compatibility with C, or is it a reason similar to the reason for C having this for having this?

Note: I've kept the mistake in the question so that answers and comments wouldn't need to be changed.

Another note: As pointed out by @Steve Summit and @matt (here), Objective-C is a strict superset of C, which means that all C code is also valid Objective-C code and thus has to show this behavior regarding functions.

markoj
  • 150
  • 10
  • 1
    For "why?" you need to ask the people who decided it that way. Probably it is like that to avoid breaking old C sources. Anyway, C allows _any_ number if you don't provide a parameter list. Or do you actually have another answer in mind? – the busybee Oct 01 '22 at 12:22

2 Answers2

2

Because function prototypes were not a part of pre-standard C, functions could be declared only with empty parentheses:

extern double sin();

All existing code used that sort of notation. The standard would have failed had such code been made invalid, or made to mean “zero arguments”.

So, in standard C, a function declaration like that means “takes an undefined list of zero or more arguments”. The standard does specify that all functions with a variable argument list must have a prototype in scope, and the prototype will end with , ...). So, a function declared with an empty argument list is not a variadic function (whereas printf() is variadic).

Because the compiler is not told about the number and types of the arguments, it cannot complain when the function is called, regardless of the arguments in the call.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

In early (pre-ANSI) C, a correct match of function arguments between a function's definition and its calls was not checked by the compiler.

I believe this was done for two reasons:

  1. It made the compiler considerably simpler
  2. C was always designed for separate compilation, and checking consistency across translation units (that is, across multiple source files) is a much harder problem.

So, in those early days, making sure that a function's call(s) matched its definition was the responsibility of the programmer, or of a separate program, lint.

The lax checking of function arguments also made varargs functions like printf possible.

At any rate, in the original C, when you wrote

extern int f();

, you were not saying "f is a function accepting no arguments and returning int". You were simply saying "f is a function returning int". You weren't saying anything about the arguments.

Basically, early C's type system didn't even have a way of recording the parameters expected by a function. And that was especially true when separate compilation came into play, because the linker resolved external symbols based pretty much on their names only.

C++ changed this, of course, by introducing function prototypes. In C++, when you say extern int f();, you are declaring a function that explicitly takes 0 arguments. (Also a scheme of "name mangling" was devised, which among other things let the linker do some consistency checking at link time.)

Now, this was all somewhat of a deficiency in old C, and the biggest change that ANSI C introduced was to adopt C++'s function prototype notation into C. It was slightly different, though: to maintain compatibility, in C saying extern int f(); had to be interpreted as meaning "function returning int and taking unspecified arguments". If you wanted to explicitly say that a function took no arguments, you had to (and still have to) say extern int f(void);.

There was also a new ... notation to explicitly mark a function as taking variable arguments, like printf, and the process of getting rid of "implicit int" in declarations was begun.

All in all it was a significant improvement, although there are still a few holes. In particular, there's still some responsibility placed on the programmer, namely to ensure that accurate function prototypes are always in scope, so that the compiler can check them. See also this question.


Two additional notes: You asked about Objective C, but I don't know anything about that language, so I can't address that point. And you said that for a function without a prototype, "trying to input an argument to it (as the first and the only argument) doesn't cause a compilation error", but in fact, you can pass any number or arguments to such a function, without error.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • Would it be fine for me to ask another question specifically for the Objective C part of this question? Also, I've kept the mistake in the question so that answers and comments wouldn't need to be changed. – markoj Oct 01 '22 at 13:09
  • 1
    I don't think that would be a problem. I would tag it objective-c only, and include a link to this question. – Steve Summit Oct 01 '22 at 13:13
  • 2
    @markoj Sorry, I guess I gave you bad advice, there. (I didn't know, or had completely forgotten, that unlike C++, Objective-C is a strict superset of C.) – Steve Summit Oct 01 '22 at 14:49