Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undefined reference to function accepted by compiler

Ok so I have this code:

str.c:

char *str = "example";

main.c:

int str(void);

int main(void)
{
    str();

    return 0;
}

makefile:

CC = gcc
CFLAGS = -Wall -g

all: main

main: main.o str.o

main.o: main.c
str.o: str.c

clean:
    rm -rf *.o main

On the first sight, one might say that it's an undefined reference error or something like that. But the compiler simply accepts this code.

The question is, why don't I get a compile error?

It's clear that the function is not properly defined. If I use gdb to break on the str() call, I get a warning type Function str not defined..

like image 339
Marian Tarlungeanu Avatar asked Jun 09 '17 14:06

Marian Tarlungeanu


Video Answer


3 Answers

First of all (as other have pointed out already) if one could have expected an error while "building" the executable main, then during the linking phase, namely because int str(void) is not defined in any translation unit (.c file) so the compiler did not place it in any object file (.o).

But unfortunately you have char * str = "..." defined.

C (as opposed to other languages, for example C++) does not annotate functions, it does not create a function-signature, but just only the function's name, a symbol name. It does so as well for all other objects.

So the linker has no other choice but checking the names of the symbols available, and if they match 1:1 to link them. It cannot double check, because the compiler did not put any verification information into the object files.

If you had an implementation (a definition, as opposed to just a declaration) of int str(void) somewhere inside the objects to link, then the linker would have noticed that there is no 1:1 match so something fishy might be going on.

like image 166
alk Avatar answered Sep 17 '22 15:09

alk


The compiler is happy if you give a function prototype int str(void);, however, the linker will try to resolve the reference and you will get an unresolved reference from it. That's where the error will come from. The prototype is your promise to the compiler that the function is defined somewhere. The linker makes sure you kept that promise.

like image 27
edtheprogrammerguy Avatar answered Sep 20 '22 15:09

edtheprogrammerguy


Compiler

Code is compiled without problems.

int str(void);   //Compiler needs this to know how to prepare future calls to this function
int main(void) {
    str();       //Here compiler knows about str function and how it looks like
    return 0;
}

When str() is called in main.c, compiler will prepare for call and since before main you have function prototype, compiler knows how to call it and will go further, he is fint with it.

Linker

Linker is the one who at the end tries to put all functions together and then you will get error like Function not found because str() function was never actually compiled.

like image 28
tilz0R Avatar answered Sep 19 '22 15:09

tilz0R