1

I have two source files test1.c and test2.c.

In test1.c:

#include <stdio.h>

void main() {
    checks(); }

In test2.c:

#include <stdio.h>

void checks(){
    printf("This is a sample Text");
    }

In this case I can successfully build and run this program.

So why should I use:

void checks();

To declare the function?

It seems perfectly fine now.

I am Using C99.

perror
  • 7,071
  • 16
  • 58
  • 85
  • 4
    It probably compiled with warnings... and you should declare the function in order to make the compiler happy – simpel01 Nov 22 '15 at 16:21
  • 1
    How are you compiling this? – Shloim Nov 22 '15 at 16:21
  • 2
    What are you asking? Are you asking why you need to declare functions before using them? Because C was defined in the 1980s where having a single-pass compiler was important for performance. – Colonel Thirty Two Nov 22 '15 at 16:21
  • 3
    `void main` this is not standard C. – edmz Nov 22 '15 at 16:22
  • @simpel01 Yap! Now I DID NOTICE there were some warnings! /home/jamius19/cpp projects/test1/main.c|6|warning: implicit declaration of function ‘checks’ [-Wimplicit-function-declaration]| –  Nov 22 '15 at 16:22
  • yap.... But it is legal, isn't it? @black –  Nov 22 '15 at 16:23
  • @ColonelThirtyTwo what you meant by "single-pass compiler"...... Can you explain? :) –  Nov 22 '15 at 16:24
  • 2
    Try with a function returning `long long`, have it return `LLONG_MAX`, test the result and get enlightened. – alk Nov 22 '15 at 16:27
  • 1
    @jamius19 It means that the compiler only goes through the source code once; thus, when compiling a statement, it only has knowledge of whatever came before the statement, so it won't know about functions you've defined later on. This was necessary for performance on the hardware around when C first came out. – Colonel Thirty Two Nov 22 '15 at 16:28
  • No, it is not. It's ill-formed since `main` must return `int`. – edmz Nov 22 '15 at 16:29
  • yap........ I understand...... but why main has to return int ? @black –  Nov 22 '15 at 16:31
  • @ColonelThirtyTwo thanks for the info :) I understand it clearly.... back then capabilities of hardware was poor.... but should we use it even with modern hardwares? And if **yes** , then why? –  Nov 22 '15 at 16:33
  • @alk could you please explain a bit? :) –  Nov 22 '15 at 16:33
  • 1
    "*I can successfully build*" a build issuing warnings I tend to consider unsuccessful. – alk Nov 22 '15 at 16:34
  • @jamius19: Just try it. – alk Nov 22 '15 at 16:35
  • 1
    @jamius19 More modern languages (C#, Java, ...) have multiple-pass compilers that allow you to use functions that you've defined at a later time, but C was created at the time where it was practical, and adding a module system to C would be a massive political and technical challenge. – Colonel Thirty Two Nov 22 '15 at 16:41
  • thanks :) @ColonelThirtyTwo –  Nov 22 '15 at 16:44
  • the funny thing is, despite using LLONG_MAX as return value and long as return type, then setting `int results = checks();` I'm still getting **-1** as output! @alk –  Nov 22 '15 at 16:45
  • 1
    @jamius19 [See here](http://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c?lq=1). – edmz Nov 22 '15 at 16:46
  • thanks for the info @black –  Nov 22 '15 at 16:48

1 Answers1

1

In your case, the check() function has a very simple prototype and the default prototype applied by the C compiler is to accept anything as argument and to return an int. It is probably what is done here (except that, as you do not store the result of the function it is optimized out without noticing it).

If you want to check my theory, try to write this (and it should work until it reaches the linking phase):

int result = check();

At the end, your code work because the linker finally find something that work to plug for the check() function (yet, it should still expect an int at some point).

In fact, the declaration of a function prototype is only useful in two cases:

  1. The code of the function and the use of the function are in the same file.

    When you use the function before its declaration (code source), then you need to tell the compiler what to expect when trying to statically type the function you are writing (the compiler read a source code file from top to bottom).

    For example:

    int bar (int a, int b, bool c);
    
    int foo (int a, bool b) {
        int result = bar (a, a, c);
        ...
    }
    
    int bar (int a, int b, bool c) {
        ...
     }
    
  2. The code of the function the use of the function are not in the same file.

    Then, you usually get the definition of the function through a header file which collect all the information needed by the compiler to know how to statically type your code. The header file (*.h) contains all the prototypes of the functions of the module you are using. The implementation of the functions will come after at linking time.

Note that, I usually try to avoid the first case because it is really not logical. When you read a source code, you go from top to bottom, just as the compiler do, and you expect to find the function definition before its usage... So, it is much more logical to structure your code in a way that do not need to require such artifacts. In my humble opinion...

perror
  • 7,071
  • 16
  • 58
  • 85
  • I used **int result = check();** but despite some warning it still worked :/ –  Nov 22 '15 at 16:37
  • 1
    @jamius19 As I already said: "*Try [...] returning `long long`*", or any other type being larger then an `int`. – alk Nov 22 '15 at 16:40
  • Ah, so it means that despite your code which states that you have a `void check()` the compiler decided to take the default prototype for `check()` and discarded the `void`. Somehow, matching the first type found is the behavior of the compiler. Not really surprising. – perror Nov 22 '15 at 16:41
  • now I'm declaring it in the **test1.c** file as `long checks();` then setting `int results = checks();` I ain't getting any error :/ @perror –  Nov 22 '15 at 16:47
  • I guess that you get as return value the content of the `rax` register at the end of the function... This example is quite good to illustrate the fact that the type-checker of C is not totally flawless and can accept dodgy things. – perror Nov 22 '15 at 17:59