C - usage of extern qualifier - c

I have following three files. In the header file, I declare a global variable and tried to access it other files using extern. But I got the linker errors.
Header1.h
#ifndef HEADER1_H
#define HEADER1_H
#include<stdio.h>
int g = 10;
void test();
#endif
test.c
#include "header1.h"
extern int g;
void test()
{
printf("from print function g=%d\n", g);
}
main.c
#include "header1.h"
extern int g;
int main()
{
printf("Hello World g=%d\n", g);
test();
getchar();
return 0;
}
Linker error:
LNK2005 "int g" (?g##3HA) already defined in main.obj
LNK1169 one or more multiply defined symbols found
My understanding about extern is that a variable can be defined only once but can be declared multiple times. I think I follow it this way - I defined the global variable g in the header file and tried to access it in the .c files.
Could you please correct my understanding? What actually causes the linker error here? I did not define g multiple times.

You get a multiple definition error because you put the definition in the header file. Because both source files include the header file, that results in g being defined in both places, hence the error.
You want to put the declaration in the header file and the definition in one source file:
In header1.h:
extern int g;
In test.c:
int g = 10;
And nothing in main.c.

Related

Unexpected Redefinition Error in CCS #10056 in Code Composer Studio

I have the problem, that in CCS I encounter unexpected redefenition errors if I include headers.
Minimal example:
// main.c
#include "test.h"
int main(void)
{
init();
return 0;
}
with
// test.h
#ifndef TEST_H_
#define TEST_H_
int var;
void init();
#endif /* TEST_H_ */
and
// test.c
#include "test.h"
void init()
{
var=0;
}
I get
error #10056: symbol "_var" redefined: first defined in "./main.obj";
redefined in "./test.obj"
on compilation. I'm pretty sure this should work in any C using IDE.
What do I miss?
" I'm pretty sure this should work in any C using IDE". No it doesn't.
Every time you include test.h in a C file, the variable var is not only declared but also defined, hence the compilation error.
Include guards are not designed to avoid multiple definitions across translation units, but more to adress multiple inclusions of the same header file in a single translation unit.
See for example https://fr.wikipedia.org/wiki/Include_guard
The proper way to adress this issue is to only declare your variable in the header file:
extern int var;
and then define the variable only once in a C file (without extern).
int var;

function declaration problem in multi file c project

I have a project that includes three files in codeblocks:
main.c :
#include <stdio.h>
#include <conio.h>
int global = 10;
void f1(int);
void f1_1(int);
void f2(void);
int main()
{
int x = 5;
printf("inside main file");
getch();
f1(x);
f2();
getch();
return 0;
}
file1.c :
#include <stdio.h>
#include <conio.h>
void f1(int x)
{
printf("\ninside file1 >> f1 and x = %i", x);
getch();
f1_1(x);
}
void f1_1(int x)
{
printf("\ninside file1 >> f1 >> f1_1 and x = %i", x);
getch();
}
file2.c :
#include <stdio.h>
#include <conio.h>
extern int global;
void f2()
{
printf("\ninside file2 >> f2 function , global var = %i", global);
getch();
}
When I compiled it, I got these warnings:
c|8|warning: implicit declaration of function 'f1_1'; did you mean 'f1'? [-Wimplicit-function-declaration]
c|11|warning: conflicting types for 'f1_1'
What should I do for this?
void f1(int);
void f1_1(int);
void f2(void);
Should be:
extern void f1(int);
extern void f1_1(int);
extern void f2(void);
Or, as #kiranBiradar points out, you can declare them in header files
file1.h
#pragma once
extern void f1(int);
extern void f1_1(int);
file2.h
#pragma once
extern void f2(void);
Note the use of the extern keyword. When you forward declare a function in a file as void f(void), the symbol 'f' is public, meaning other compilation units can reference it. When you declare it as extern void f(void), then the compiler doesn't expect the function to be defined in that compilation unit and leaves it up to the linker to find that symbol.
This is the perfect time to learn about the important concept of translation units.
Each single source file, with all included header file, forms a single translation unit. Each translation unit is separate and distinct and compiled stand-alone without any knowledge of other translation units.
That means symbols declared in e.g. the main.c source file will not be known in the file1.c source file.
When you compile file1.c the compiler simply doesn't know about the f1_1 function declaration you have in the main.c source file, so you get a warning about that fact.
To solve your problem, you need to declare the f1_1 function in the file1.c file. Either by adding a forward declaration (like the one you have in main.c), or moving the whole function definition (implementation) of f1_1 above the f1 function.
Or you could create a single header file which contains all the declarations needed (for the f1, f1_1, f2 function, plus the global external variable declaration), and include this single header file in all your source files. This solution works best if you have multiple symbols (functions, variables, etc.) that are used in multiple translation units.
My personal recommendation is this: Since the f1_1 function is only used internally inside the file1.c source file, move its definition above f1, and make it static. Then remove its declaration from the main.c source file.
Regarding the "implicit declaration" and "conflicting types" warnings, it's because in older standards of C it was allowed to not declare functions and the compiler would create an implicit declaration by guessing the declaration based on the first call of the function.
The important part about the guessing is that only the arguments were guessed, the return type would always be int.
I don't know the exact wording in the specifications about this since it was removed in the C99 specification, but most compilers still allow this with only emitting a warning instead of an error. This is where the first warning comes from.
However, the return type of int is still being used. And since your f1_1 function is declared to return void later in the file1.c source file, there's a mismatch between the guessed declaration (int f1_1(int)) and the actual declaration (void f1_1(int)) which leads to the second warning.

Use of modifier static in c

I'm a beginner learning c. I know that use of word "static" makes a c function and variable local to the source file it's declared in. But consider the following...
test.h
static int n = 2;
static void f(){
printf("%d", n);
}
main.c
#include <stdio.h>
#include "test.h"
int main()
{
printf("%d", n);
f();
return 0;
}
My expected result was that an error message will throw up, since the function f and variable n is local to test.h only? Thanks.
But instead, the output was
2
2
EDIT:
If it only works for a compilation unit, what does that mean? And how do I use static the way I intended to?
static makes your function/variable local to the compilation unit, ie the whole set of source code that is read when you compile a single .c file.
#includeing a .h file is a bit like copy/paste-ing the content of this header file in your .c file. Thus, n and f in your example are considered local to your main.c compilation unit.
Example
module.h
#ifndef MODULE_H
#define MODULE_H
int fnct(void);
#endif /* MODULE_H */
module.c
#include "module.h"
static
int
detail(void)
{
return 2;
}
int
fnct(void)
{
return 3+detail();
}
main.c
#include <stdio.h>
#include "module.h"
int
main(void)
{
printf("fnct() gives %d\n", fnct());
/* printf("detail() gives %d\n", detail()); */
/* detail cannot be called because:
. it was not declared
(rejected at compilation, or at least a warning)
. even if it were, it is static to the module.c compilation unit
(rejected at link)
*/
return 0;
}
build (compile each .c then link)
gcc -c module.c
gcc -c main.c
gcc -o prog module.o main.o
You have included test.h in main.c.
Therefore static int n and static void f() will be visible inside main.c also.
When a variable or function is declared at file scope (not inside any other { } brace pair), and they are declared static, they are local to the translation unit they reside in.
Translation unit is a formal term in C and it's slightly different from a file. A translation unit is a single c file and all the h files it includes.
So in your case, the static variable is local to the translation unit consisting of test.h and main.c. You will be able to access it in main.c, but not in foo.c.
Meaning that if you have another .c file including test.h, you'll get two instances of the same variable, with the same name. That in turn can lead to all manner of crazy bugs.
This is one of many reasons why we never define variables inside header files.
(To avoid spaghetti program design, we should not declare variables in headers either, unless they are const qualified.)

Error when building c code with -D

I get the following errors when I'm trying to build my c code files with -D. But, if I build it without -D, it works. I don't know why. Thanks. (My machine is ubuntu12.10, 32bit)
gcc c1.c c2.c -D DEBUG
/tmp/ccX04EIf.o:(.data+0x0): multiple definition of `g'
/tmp/cc0j9MoU.o:(.data+0x0): first defined here
collect2: ld returned 1 exit status
Here is my source code:
global.h
#ifdef DEBUG
int g = 23;
static int init = 1;
#else
int g;
static int init = 0;
#endif
c1.c
#include "global.h"
int f() {
return g + 1;
}
c2.c
#include <stdio.h>
#include "global.h"
int main() {
if (!init) {
g = 37;
}
int t = f();
printf("calling f yields %d\n", t);
return 0;
}
You define the variable g in the header file, that means it will be defined in all source files that includes the header file.
Instead declare it, like
extern int g;
and then define it in a single source file.
The difference between the two code paths (with and without DEBUG) is the initialization of the g variable. Without it, it is only a "tentative" definition, and so the symbol is only generated in the file that really uses it, namely c2.o.
With initialization it is a real definition of the symbol, and so it is also generated in c1.o.
As a rule of thumb, header files should never contain data definitions, only declarations. Data "declarations-only" should be made with the keyword extern. You'd then need to define any such symbol in exactly one of your .c files.

Duplicate symbol in C using Clang

I am currently working on my first "serious" C project, a 16-bit vm. When I split up the files form one big source file into multiple source files, the linker (whether invoked through clang, gcc, cc, or ld) spits out a the error:
ld: duplicate symbol _registers in register.o and main.o for inferred
architecture x86_64
There is no declaration of registers anywhere in the main file. It is a uint16_t array if that helps. I am on Mac OS 10.7.3 using the built in compilers (not GNU gcc). Any help?
It sounds like you've defined a variable in a header then included that in two different source files.
First you have to understand the distinction between declaring something (declaring that it exists somewhere) and defining it (actually creating it). Let's say you have the following files:
header.h:
void printIt(void); // a declaration.
int xyzzy; // a definition.
main.c:
#include "header.h"
int main (void) {
xyzzy = 42;
printIt();
return 0;
}
other.c:
#include <stdio.h>
#include "header.h"
void printIt (void) { // a definition.
printf ("%d\n", xyzzy);
}
When you compile the C programs, each of the resultant object files will get a variable called xyzzy since you effectively defined it in both by including the header. That means when the linker tries to combine the two objects, it runs into a problem with multiple definitions.
The solution is to declare things in header files and define them in C files, such as with:
header.h:
void printIt(void); // a declaration.
extern int xyzzy; // a declaration.
main.c:
#include "header.h"
int xyzzy; // a definition.
int main (void) {
xyzzy = 42;
printIt();
return 0;
}
other.c:
#include <stdio.h>
#include "header.h"
void printIt (void) { // a definition.
printf ("%d\n", xyzzy);
}
That way, other.c knows that xyzzy exists, but only main.c creates it.

Resources