This question already has answers here:
Xcode - Warning: Implicit declaration of function is invalid in C99
(4 answers)
Closed 9 years ago.
I got another question in C programming. I followed an example in the Book "Programming in C" and wrote the following two source files:
main.c:
#include <stdio.h>
#include <stdlib.h>
int i = 5;
int main(void)
{
printf("%i ", i);
foo();
printf("%i\n", i);
return 0;
}
and
foo.c:
extern int i;
void foo(void)
{
i = 100;
}
Problem arises when I compile 'gcc main.c foo.c':
main.c:9:3: warning: implicit declaration of function 'foo' is invalid
in C99 [-Wimplicit-function-declaration] foo(); ^ 1 warning
generated.
I found a work around by renaming foo.c to foo.h and include it as header in main.c. Is this a good way of making it work? How to make it work with foo.c ?
You need a header with declaration of the function foo. Leave foo.c as is and create foo.h with the declaration
void foo(void);
Then include foo.h in main.c and in foo.c:
#include "foo.h"
You need to define the signature of foo in a header and include it in main.c
foo.h:
void foo(void);
in main.c:
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"
// Rest of code
Related
I'm new to C, just a question on global variable, below is the code that uses the header file as recommended:
//test.h
extern int globalVariable;
//test.c
#include "test.h"
int globalVariable = 2020;
//main.c
#include <stdio.h>
#include "test.h"
int main()
{
printf("Value is %d", globalVariable);
}
so it works well and the print output is 2020.
But if I change the main.c as:
#include <stdio.h>
#include "test.h"
int globalVariable;
int main()
{
printf("Value is %d", globalVariable);
}
it still compile and the output is still 2020. Below is my question:
Q1-When I add int globalVariable; in main.c, isn't that it re-initialize the globalVariable to 0 becuase int globalVariable; is the same as int globalVariable = 0;. So why the output is still 2020 rather than 0?
Q2-globalVariable is already defined in test.c, and I re-define(reinitialize) it to 0, should it be a compile error since C doesn't allow multiple definition, so why the program still compile?
This declaration at file scope:
int globalVariable;
Is a tentative definition. It has no initializer and is not static. GCC can "fold" tentative definitions together from multiple translation units into a single identifier. This is not specified by the standard but is an extension supported by GCC.
In this case the tentative definition in main.c gets rolled into the the complete definition in test.c and initialized with the given value. If you were to use an initializer in main.c as well, then you would get a multiple definition error.
I am trying to create a struct in a header file, and initialize a template struct. For some reason, when including the header file in multiple files, it gives me the following error:
gcc foo.c bar.c -o foo -Wall
duplicate symbol _MYFOO in:
/var/folders/s4/zyw5lgk92wj9ljnsypgwdccr0000gn/T/foo-52f8fc.o
/var/folders/s4/zyw5lgk92wj9ljnsypgwdccr0000gn/T/bar-6dc21f.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
These are my files:
Bar.c:
#include "bar.h"
#include <stdio.h>
void helloWorld() {
printf("Hello world\n");
}
Bar.h
typedef struct Foo Foo;
struct Foo {
int number;
} MYFOO = {2};
void helloWorld(void);
Foo.c
#include "bar.h"
int main() {
helloWorld();
}
Interestingly enough, when I remove the line containing
MYFOO = {2};
The code compiles and works perfectly fine. I believe it has to do with including Bar.h twice, which ends up including that struct twice? But how would I avoid something like that?
Thank you!
You could add a directive to the Bar.h file to check if the file has already been included:
#ifndef _BAR_H_INCLUDED_
// Bar.h not included - declare your structs, etc, here.
// Define _BAR_H_INCLUDED_ to indicate this file has already
// been included
#define _BAR_H_INCLUDED_ 1
#endif
This should at least prevent you including Bar.h multiple times.
EDIT
A better solution might be to include the Bar.c from within the Bar.h:
// Bar.h
#ifndef _BAR_C_INCLUDED_
// code here
// Include Bar.c
#include "Bar.c"
#define _BAR_C_INCLUDED_
#endif
You can then simply include Bar.h in your Foo.c:
// Foo.c
#include <stdio.h>
#include <stdlib.h>
#include "Bar.h"
int main() {
//...
Then to compile:
gcc Foo.c -o Foo
So - here is your updated code - first, Bar.h
#ifndef _BAR_C_INCLUDED_
typedef struct Foo Foo;
struct Foo {
int number;
} MYFOO = {2};
void helloWorld (void);
#include "Bar.c"
#define _BAR_C_INCLUDED_
#endif
Now Bar.c:
void helloWorld() {
printf("Hello world\n");
}
Lastly, Foo.c - include stdio.h here as well as Bar.h (which will, in turn, include Bar.c for us):
#include <stdio.h>
#include "bar.h"
int main() {
helloWorld();
}
And to compile:
gcc Foo.c -o Foo -Wall
After toying around some more, I found the reason for the error coming from the line MYFOO = {2};
It had to do with the fact that I was initializing the struct in my header file.
Header files are meant for definitions, not initializations.
Instead, the solution for the problem was to simply define and initialize the line in the corresponding source file Foo.c.
Now, in that file I included as a global variable:
Foo MYFOO = {2};
Now to access this variable in any other file, such as in my Bar.c, all I needed to do was include the line,
extern Foo MYFOO;
This solved my problem for compilation and meant that I could use the struct in other files as desired!
consider the following code, which causes a weird behavior:
foo.h
#ifndef FOO_H
#define FOO_H
void foo();
#endif
foo.c
#include <stdio.h>
// NOTICE - foo.h is not included!
void foo()
{
printf("foo!\n");
}
main.c
#include "foo.h"
int main()
{
foo();
return 0;
}
running this code I get in the console: foo!
what bugs me here is that I expected that main.c would not be familiar with the implementation of foo(), since foo.h is not included in foo.c, and hence foo() should be an inner function in foo.c. It happened to me both when I ran it in VS2010 and when I compiled an exe using gcc (on windows).
can someone explain this phenomenon? I thought about it and I have no idea why it happens. thanks.
The header file is declaring the function, so when compiling main.c the compiler knows the function signature to validate against. When compiling foo.c, it doesn't need to be declared, as it is the declaration of the function. It is up to the linker to see if there are any unresolved symbols, which there aren't in this case, so all is good, and also why you're seeing this work.
What will happen if there was another function(test.c) included in the above question.
foo.h
#ifndef FOO_H
#define FOO_H
void foo();
#endif
foo.c
#include <stdio.h>
// NOTICE - foo.h is not included!
void foo()
{
printf("foo!\n");
}
test.c
#include <stdio.h>
void foo()
{
printf("foo!\n");
}
main.c
#include "foo.h"
int main()
{
foo();
return 0;
}
From this article Unit testing with mock objects in C:
This is done by using the --wrap linker option which takes the name of the wrapped function as an argument. If the test was compiled using gcc, the invocation might look like:
$ gcc -g -Wl,--wrap=chef_cook waiter_test.c chef.c
How can I do this when compiling a C project in visual studio?
The --wrap in ld can be emulated by the /ALTERNATENAME option in MSVC Linker.
We start from two compilation units, say foo.o compiled from foo.c, whose external functions are declared in foo.h, and main.o from main.c.
(If foo has been compiled as a library, things won't change much.)
// foo.h
int foo();
// foo.c
int foo() {
return 0;
}
// main.c
#include <stdio.h>
#include "foo.h"
int main() {
int x = foo();
printf("%s\n", x ? "wrapped" : "original");
}
The return value of int foo() is 0, so the snippet of code above will output "original".
Now we override the actual implementation by an alias: The #include "foo.h" in main.c is replaced by
#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")
Let me explain what happens here:
by #define foo real_foo, the function declaration in foo.h is modified as int real_foo().
However, the symbol in foo.o is still named after int foo(), instead of the alias int real_foo(). That's why we need the /alternatename linker switch.
"/alternatename:real_foo=foo" tells the linker that, if you cannot find the symbol called real_foo, try foo again before throwing an error.
Apparently there is no definition of int real_foo(). MSVC Linker will search for int foo() and link it instead at each occurrence of int real_foo().
As the previous implementation has been aliased, now we redirect int foo() to our new implementation by a macro:
int wrap_foo() {
return real_foo() + 1;
}
#define foo wrap_foo
And we are done here. At last the main.cpp looks like:
#include <stdio.h>
#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")
int wrap_foo() {
return real_foo() + 1;
}
#define foo wrap_foo
int main() {
int x = foo();
printf("%s\n", x ? "wrapped" : "original");
}
Built in MSVC, it will output "wrapped".
These are my code files:
header.h
#ifndef HEADER_H
#define HEADER_H
extern int bar;
#endif
foo.c
#include <stdio.h>
#include "header.h"
void foo(void) {
printf("foo: bar = %d\n", bar);
printf("foo: ++bar = %d\n", ++bar);
}
main.c
#include <stdio.h>
#include "header.h"
int main(void) {
int bar=0;
printf("main: bar = %d\n", bar);
printf("main: ++bar = %d\n", bar);
foo();
return 0;
}
When I try to compile those in Ubuntu:
gcc -c foo.c
gcc main.c foo.o -o program
I get this error from the linker:
/tmp/ccWHhwtm.o: In function `foo':
foo.c:(.text+0x6): undefined reference to `bar'
foo.c:(.text+0x1d): undefined reference to `bar'
foo.c:(.text+0x26): undefined reference to `bar'
foo.c:(.text+0x2c): undefined reference to `bar'
collect2: error: ld returned 1 exit status
As I have seen from other answered questions here, in order to share a global variable to multiple files, you will just have to declare the variable in the header file using extern keyword and define it in one of the .c codes.
That is what I have done here, but I get this error.
What is happening ?
bar should be defined in file scope:
#include <stdio.h>
#include "header.h"
int bar=0;
int main(void) {
....
When I was typing: "What is happening", just then, ironically, I figured out the answer :-P.
The problem is that I define the variable inside main function. Thus the definition scope is limited between the braces.