It is a dumb question, I admit. Code will explain it better. Got these files:
hello.c:
#include <stdio.h>
void hello(char * s)
{
printf("hello, %s\n", s);
}
main.c:
int main()
{
hello("world!");
return 0;
}
makefile:
test : main.o hello.o
gcc -o test main.o hello.o
main.o : main.c
gcc -c main.c
hello.o : hello.c
gcc -c hello.c
.PHONY : clean
clean :
-rm test
-rm main.o
-rm hello.o
I can just "make" and "./test" it and it works.
Shouldn't I need to include something like hello.h in main.c just so the compiler knows the function prototype?
I didn't even include hello.c anywhere and it just works! How come main.c knows about the hello function?
If that works, when do I need .h files? I am new to C programming but I thought this concept was easy to grasp, now I am completely confused.
If you use the -Wall flag (and one should always use it, along with -Werror -Wextra), then you'd get the following message:
main.c: In function 'main':
main.c:3: warning: implicit declaration of function 'hello'
And the compiler effectively "guesses" what to do, which can lead to disaster in many circumstances.
Correctly using header files avoids this sort of warning.
You do not need header files; instead, your functions need prototypes. When you call hello passing it "world", C figures out that you are calling a one-argument function taking char*, and does everything right. This will not work, however, if the function takes a float, and you decide to ass it an int (try it, it is very instructive). For reasons of backward compatibility C will let you call functions without prototypes, but it is dangerous. For example, in case of your call of hello, the compiler thinks that you are calling a function returning an int. Technically, you are invoking undefined behavior, so your program works by accident.
Headers happen to provide the most convenient way to supply prototypes, but you can supply them in the code itself, like this:
void hello(char*);
int main()
{
hello("world!");
return 0;
}
Related
I have one lib which contains a file (called Util.c down here), and i'm trying to use some funtions defined in this file to compile a little prog. I'm already using others functions from the lib, but the ones of this particular file always give me back an "Undefined Reference". What's really weird is: the others functions from the lib does use functions from Util.c, and that's working well. It's just that...i can't use them directly.
I'll try to give you a clear view of the things here:
Util.c
void foo (void *var){
print ("in Foo!");
}
void *bar (int var){
print ("in bar!");
}
Util.h:
#ifndef UTIL_DEFINED
#define UTIL_DEFINED
void foo(void *var)
void *bar(int var)
#endif
libobj.c:
#include "Util.c"
// #include "a lot of other files.c"
MyFile.c:
#include "Util.h"
// #include "others headers from the lib which functions are working well"
int main(){
//here i use the lib's function without a prob, except for the ones coming from Util.c, namely foo and bar. For example:
int *var;
//Say that LibFunc is another function from the lib, but not from Util.c.
//Libfunc make a call to foo, and it's working well.
Libfunc(var);
//However, here i try to use foo or bar, and i get the undefined reference!
foo(var);
bar(var);
}
The Makefile is a big thing, but if i search only for the parts related to the lib, it looks like it:
Lib Makefile
default: $(LIB)
$(LIB): $(LIBOBJ)
-$(RM) "$#"
$(DLLD) -o "$#" $(DLLDFLAGS) "$(LIBOBJ)"
$(LIBOBJ): libobj.c $(LIBSRC) $(LIBINC)
$(CC) -c $(LOTOFFLAGS) libobj.c -o "$#"
LIBSRC: libobj.c\
aBunchOfOtherFiles.c
LIBINC: Util.h\
ABunchOfHeadersFiles.h
LIBOBJ=$(LIBNAME)dll.o
LIB=$(LIBNAME).dll
CC= gcc
DLLD = gcc -shared -fprofile-arcs -ftest-coverage -fprofile-generate
DLLDFLAGS = -fPIC
LOTOFFLAGS = -Wall -pedantic -Wno-long-long -Wno-unused-function -g -g3 -ggdb -std=c99 --coverage -fprofile-arcs -ftests-coverage -fprofile-generate -Wl,--allow-multiple-definition -fPIC $(IFLAGS)
#IFLAGS include all headers files, as well as some info concerning Lib version, OS, PROC, etc... not so important here.
IFLAGS = -I$(FOLDERS) -DWINDOWS
FOLDERS= MyFolders
LIBNAME = MyLibName
RM= del
And finally, my makefile looks like it:
My Makefile
default: $(PROG_EXE)
$(PROG_EXE) : $(LIB) $(PROG_OBJ)
$(CC) $(SOMEFLAGS) $(PROG_OBJ) "$(LIB)" -o "$#"
$(PROG_OBJ) : MyFile.c $(LIBINC)
$(CC) -c $(SOMEFLAGS) -$(IFLAGS) MyFile.c -o "$#"
LIB = $(LIBNAME).dll
LIBINC = Util.h\
ABunchOfHeadersFiles.h
PROG_EXE= MyProg
PROG_OBJ = MyProg.o
CC= gcc
SOMFLAGS = -Wall -std=c99 -pedantic -g -g3 - ggb -fprofile-arcs -ftests-coverage
#IFLAGS basically include all folders containing source code and headers. Also gives some D, such as OS, PROC or the lib version. Not really important for my prob.
IFLAGS = -I$(FOLDERS) -DWINDOWS
FOLDERS = MyFolders
LIBNAME = MyLibName
Note that i didn't made any of that. I'm just supposed to make it works...
I've tried to get all the flags (think i got them all). Some of them are only for the use of gcov, others just to include the good folders and files. I've already checked: Util.c and Util.h are correctly included in thoses. BTW, when i compil MyProg, i don't have the "file not found" error on Util.h, so it is found.
Also, i've seen that foo is supposed to get a void* and is actually given a int*. But i don't think it's the problem here, since when i compile MyProg using directly Util.c, without trying to get it from the lib, it works well.
So i really think that, somehow, my prog can't find the functions in the lib. But it does found the header well, and it does found others functions from the lib well, and those functions use the ones froms Util.c, so i just don't get it :'(
Plus, i've tried to compile the lib WITHOUT Util.c, just to be sure that the lib really uses it. Then i got the same "undefined reference", so it seems that the lib correctly includes Util.c
PS: i'm on windows 32bits, if that is of any use...
I think the mistake comes from libobj.c file:
#include Util.c
The quotation marks are missing:
#include "Util.c"
In General we #include the .h and not the .c.
I've found a way to make it works, even if i still can't understand the problem.
It seems that, in Windows using Mingw, you have to add __declspec( dllexport ) in front of each function you wanna use from outside of the dll.
So, if i change my Util.c this way:
`__declspec( dllexport ) void foo (void *var){
print ("in Foo!");
}
`__declspec( dllexport ) void *bar (int var){
print ("in bar!");
}
I think this lib is somehow set so that it has "publics" and "privates" functions; until now i was just using the public ones, and the ones inside Util.c are private. It's the only explanation i see, even if i had no idea how to makes function privates or public.
This question already has answers here:
Are prototypes required for all functions in C89, C90 or C99?
(6 answers)
Closed 7 years ago.
I have a C file (say file1.c) that calls a function
fun1(1,b).
This function fun1(int a,int b) resides in another C file (say file2.c) but its prototype is not included in the header file (say file2.h).
file2.h is included in file1.c.
My question is, if I call fun1(a,b) from file1.c, will it work by passing control to the function definition in file2.c? Or will an exception occur or what will be the expected behavior?
Do I have to give a prototype of fun1(int a, int b) in file2.h for this to work?
A couple things can happen depending on the situation and your compiler:
You get a compilation error. The compiler throws up its arms and refuses to produce an object file.
The compiler treats the function declaration as implied by the call and proceeds to link. It may assume that you know what you're doing in terms of function arguments. Usually it also assumes an int return type. Almost every compiler I've worked with will produce a warning when it does this.
The compiler treats the declaration as implied by the call but fails to link. Like the above, but the linker then notices that the implied function you're trying to call and the one you actually did write are different and dies.
You SHOULD provide a prototype regardless.
Expected behaviour is that your functions will get called, provided the object files are linked together. Any undeclared function, is assumed to be an external function that returns an integer for compile purpose, and an external symbol (to the object file) for purposes of linking. I'll give you concrete example:
foo.c:
void foo(const char *name) {
printf("foo called with %s\n", name);
}
bar.c:
void bar(int a) {
printf("bar called with %d\n", a);
}
main.c:
int main(int argc, char *argv[]) {
foo("Hello");
bar(5);
return 0;
}
Compiling the object files using gcc:
gcc -fno-builtin -ansi -c -o foo.o foo.c
gcc -fno-builtin -ansi -c -o bar.o bar.c
gcc -fno-builtin -ansi -c -o main.o main.c
These should not produce any warnings or errors
Now link them together:
gcc -o progy main.o bar.o foo.o
Note that i used gcc to link the binaries, but that is equivalent of:
ld -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o progy /usr/lib64/crt1.o /usr/lib64/crti.o /usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.1/crtbegin.o main.o foo.o bar.o -lc -L/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.1 -lgcc -lgcc_s /usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.1/crtend.o /usr/lib64/crtn.o
on my Linux 64-bit platform. (GCC actually runs LD like this to do the linking)
Using your C compiler (in my case gcc) for linking will ensure that linker is called correctly for whatever your build target platform is. If you use an IDE then these steps are all hidden by a nice interface.
After some talking about linking in ##C on irc.freenode.net, I went to test some concepts I learned, and came up with this situation.
I have this file, named main.c:
int main(void) {
func();
return 0;
}
And this file, named test.c:
#include <stdio.h>
void func(void) {
printf("Hello.\n");
}
There's no test.h file.
I do this:
$ gcc -c main.c
$ gcc -c test.c
$ gcc main.o test.o
$ ./a.out
Hello.
$
and that works. Shouldn't gcc complain, on its first call, about not knowing function func() that is called in the main.c file? I didn't include any file with its prototype or implementation, and yet gcc can compile an object code and make a sane executable. What happened there that I'm missing?
Thank you.
Turn on a few warnings and you will be made painfully aware of the problems.
> gcc -Wall -c main.c
main.c: In function ‘main’:
main.c:2:5: warning: implicit declaration of function ‘func’
C will by default assume things about unknown functions. Good? Probably not. Historical.
Also gcc -std=c99 will throw the warning as well.
It works because all the argument types are matching (since you don't have anyone). You can make gcc complain by calling it gcc -c -Wall test.c
I already know the differences between a header file and a library. However, when I'm writing my makefile, I have some difficulties on deciding if I should put something as a dependency of the file or just at the linking rule.
For example: I have 2 simple files:
main.c:
#include <stdio.h>
main(){
printf("this is the sine or 90");
sinus(90);
}
and func.c:
#include <math.h>
sinus(int num){
return sin(num);
}
and my makefile is:
main: main.o func.o
gcc main.o func.o -lm -o main
func.o: func.c
main.o: main.c
Well, my question is why this makefile works and this one doesn't:
main: main.o func.o
gcc main.o func.o -lm -o main
func.o: func.c math.h
main.o: main.c
You don't need to make func.o depend on math.h as that file is very unlikely to change.
Regarding the error you get if you do is because you don't explicitly specify how make should compile the file so it tries to deduce how to compile it and it only works in simple cases. I'm not sure exactly how make does it but I think it just does gcc -o target.o -c <your deps>.
Because make is looking for a file "math.h" in the current directory and trying to do cc func.c math.h to produce func.o
Problem is that you don't know exactly how Makefile is resolved after using implicit rules - definitely there's one which causes problems you have. (maybe try to compile math.h, or math.h is not found etc.. (you didn't posted errors you have so we can only speculate).
I would advice you to disable implicit rules by calling make with "-r" and do everything explicitly - this way you will learn more as you'll know how makefile works instead of knowing how to write makefiles which works under some circumstances.
More on implicit rules: Make documentation - Implicit rules
More on make Make documentation
I've just organized my code by using headers, but just as I've done this, I got a warning that turned into an error when linking.
I have a code(use of a function that is inside a header) in test.c that is like this:
#include "test1.h"
/* Some code */
main()
{
Testing();
}
And my test1.h header is like this:
void Testing();
void print(int, int, int, const char*);
And at test1.c
void Testing()
{
print(0xF9, 27, 5, "\xC9\\xBB");
}
void print(int colour, int x, int y, const char *string)
{
volatile char *video=(volatile char*)0xB8000 + y*160 + x*2;
while(*string != 0)
{
*video=*string;
string++;
video++;
*video=colour;
video++;
}
}
When I try to compile the code, I got this:
ubuntu#eeepc:~/Development/Test$ gcc -o test.o -c test.c -Wall -Wextra -nostdlib -nostartfiles -nodefaultlibs
test.c: In function ‘main’:
test.c:11: warning: implicit declaration of function ‘Testing’
ubuntu#eeepc:~/Development/Test$
At the time it's just a simple warning, but when I try to link it...
ubuntu#eeepc:~/Development/Test$ ld -T linker.ld -o kernel.bin loader.o test.o
test.o: In function main':
test.c:(.text+0xfc): undefined reference toTesting'
What I need to do?
Edit: To reflect the OP's question I have struck out some lines of my answer despite being upvoted...
Why is kernel.c flagged up in the compiler, even though you don't have it mentioned here? Am I missing something...
gcc -o test.o -c test.c -Wall -Wextra -nostdlib -nostartfiles -nodefaultlibs
kernel.c: In function ‘main’:
kernel.c:11: warning: implicit declaration of function ‘Testing’
ubuntu#eeepc:~/Development/Test$
maybe you need to do it this way somewhere in your header file as I'm judging you want kernel to access this function:
extern void Testing();
And, take out all your functions and place them in a separate .c file, they should not be in there in the first place... for example:
Testing.c
/* all your functions here */
Testing.h
/* Only global, external variables and function prototypes */
Hope this helps,
Best regards,
Tom.
I can't recreate your problem. This works as expected when I try to compile your code on an Ubuntu machine (Which based on your paste, I assume you're using.)
Are you sure the #include is happening correctly?
Try using -E instead of -c to see what the whole code the compiler is trying to compile looks like.
Somewhat of a shot in the dark here, since my C is a bit rusty, but does C allow you to put function bodies in a header? I don't recall that it does. Try moving the definition of Testing() and print() into a .c file? You could also try compiling as C++ as see if that fixes it, if you don't need/want C.
You included test.h into main.c, while your declarations, according to what your wrote, are in test1.h. Note the 1 in the name.
In addition to that, you are compiling test.c and linking test.o, while in reality the name of your file is test1.c. Again, note the 1 in the name.
Edit: Now you edited the name of the file included into main.c. After the edit it is safe to assert that most of the symptoms you describe are not possble with the current versions of the files. Re-verify what you are doing, post updated disgnostic information and/or post real code.
Still, you compiler and linker lines are referring to old file names.
i donno whats causing this , but i had this problem just now .
try to delete the .h file and put the declarations of the functions on the top of .c file itself .
in this case , delete the test1.h and put the declarations of functions of test1.c in test1.c.
and include test1.c in test.c
you wont get that warning message any more , nor the following linking errors .