Why does an invalid use of C function compile fine without any warnings?

I'm more like C++ than C, but this simple example of code is big surprise for me:

int foo() {
    return 3;
}

int main() {
    int x;
    foo(&x);
    return x;
}

https://godbolt.org/z/4ov9nTzjM

No warnings, no linking issues still this code is invalid.

I've stumbled on this when some beginner filed a question with code having this strange issue. Question was asked on some other site (none English one) and I'd like to provide him better explanation why it compiles (and learn something about C). His original code if some one needs to see it.

I'm suspecting that this sis somehow related to implicit function declaration, but I'm not fully sure. Why compiler doesn't complain that foo is called with arguments?

Update:

Here is an assembly:

foo:
        push    rbp
        mov     rbp, rsp
        mov     eax, 3
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        lea     rax, [rbp-4]
        mov     rdi, rax
        mov     eax, 0
        call    foo
        mov     eax, DWORD PTR [rbp-4]
        leave
        ret

as you can see x remains uninitialized.


Solution 1:

The compiler should issue a message for this program

int foo() {
    return 3;
}

int main() {
    int x;
    foo(&x);
    return x;
}

because the function foo called with an argument though its identifier list is empty. So the program has undefined behavior.

According to the C Standard *6.7.6.3 Function declarators (including prototypes) )

14 An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.

So the program is invalid.

You could make it a valid program the following way

int foo();

int main() {
    int x;
    foo(&x);
    return x;
}

int foo( int *p ) {
    return 3;
}

Though the compiler can issue a warning that the parameter p is not used.

In this case the function declaration that is not its definition means that there is no information about the number and types of parameters.

Opposite to C in C++ this declaration

int foo();

is equivalent to

int foo( void );

Solution 2:

This function is 100% correct.

In the C language int foo() { means: define function foo returning int and taking unspecified number of parameters.

Your confusion comes from C++ plus where int foo(void) and int foo() mean exactly the same.

In the C language to define function which does not take any parameters you need to define it as:

int foo(void) {