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.)
Related
//a.c
#include <stdio.h>
#include "b.c"
void main()
{
int var;
var = increment();
var = increment();
var = increment();
count = count + 3;
var = count;
printf("%d", var);
}
//b.c
static int count;
int increment()
{
++count;
return count;
}
Now as in b.c file I have a variable with name count and is static. Now this variable should not be accessible in a.c directly but in my case I can access and manipulate it. So am I missing something?
OUTPUT
6
#include "b.c" in a.c makes b.c a part of the compilation of a.c; they are compiled as one source file.
To keep identifiers in separate source files separate, you compile them separately, without using #include to include one in the other. The separate compilations produce separate object files (.o files on Unix and Unix-like systems), which you then link together with a link command (which may be included in or performed by the gcc command).
Separating the source files also separates an identifier you do want to share between the two files, the function named increment. So a.c will not know about increment, and the compiler will complain. To deal with this for a single function, you can simply declare the function in a.c with extern int increment();. However, the usual technique for managing this sharing of identifiers is:
Create a file named b.h that declares identifiers to be defined in b.c but shared with other source files.
In b.h, declare increment with extern int increment();.
In any source file that will use identifiers from b.c, include b.h with #include "b.h".
In b.c, also include b.h. This provides a check that the declarations in b.h match the definitions in b.c, because the compiler will see both while compiling b.c and report inconsistencies.
You've included b.c in a.c, so they become a single unit as far as the compiler is concerned. Because of this, you can see the static variable.
If you removed the include line, you wouldn't see either count or increment, although the latter would be implicitly declared because it is a function.
I declared a global static function in one file
a.c
static void Func1(void);
void Func2(void);
void Func1(void) {
puts("Func1 Called");
}
void Func2(void) {
puts("Func2 Called");
}
and accessed it in b.c
#include <stdio.h>
#include "a.c"
void main() {
Func1();
Func2();
}
the program complied successfully, but as per provided information this should give error: undefined reference to Func1. What wrong is happening here?
You don't include a source file in another, you compile and link them together.
In you case, by saying #include "a.c", you're essentially putting the whole content of a.c into b.c and then starting the compilation, so the static functions and their calls are present in the same translation unit. Thus, there is no issue for compiler to find the called function.
Instead, if you do something like
gcc a.c b.c -o a.out //try to compile and link together
you'll see the expected error, as in this case, a.c and b.c will be two separate translation units.
You declare in header files and define in .c files. So you must use header files to represent the variables or functions you defined. Instead if you use .c files then it leads to multiple definitions.I think that is why you can access that global function.
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.
I have two source files:
Source FIle 1 (assembler.c):
#include "parser.c"
int main() {
parse_file("test.txt");
return 0;
}
Source File 2 (parser.c):
void parse_file(char *config_file);
void parse_file(char *src_file) {
// Function here
}
For some reason, when compiling it is giving me the following error:
duplicate symbol _parse_file in ./parser.o and ./assembler.o for architecture x86_64
Why is it giving me a duplicate symbol for parse_file? I am just calling the function here... No?
First off, including source files is a bad practice in C programming. Normally, the current translation unit should consist of one source file and a number of included header files.
What happens in your case is that you have two copies of the parse_file function, one in each translation unit. When parser.c is compiled to an object file, it has its own parse_file function, and assembler.c also has its own.
It is the linker that complains (not the compiler) when given two object files as an input, each of which contains its own definition of parse_file.
You should restructure your project like this:
parser.h
void parse_file(char *);
parser.c
void parse_file(char *src_file) {
// Function here
}
assembler.c
/* note that the header file is included here */
#include "parser.h"
int main (void) {
parse_file("test.txt");
return 0;
}
You're including the parser.c file, which means all the code that is in that file will be "copied" to assembler.c file. That means that the entire contents of parser.c will be compiled when the compiler is compiling parser.c, and then it'll be compiled again when the compiler is compiling assembler.c
That's what headers are for.
In the header you can put only the declarations, so you can include it without creating the same symbols again in a different translation unit.
so you can just create a parser.h containing just the declaration of the function:
void parse_file(char *config_file);
then in your assembler.c you include just the header:
#include "parser.h" //include the header, not the implementation
int main() {
parse_file("test.txt");
return 0;
}
You are including the .c file which contains the definition of the function parse_file. Thus it is defined twice, once in each translation unit, which is not allowed.
As other answers state, including the source means the file will be copied to parser.c and will be defined there as well in the original place (assembler.c). To solve this, either create a header file with your prototype:
parser.h
void parse_file(char *config_file);
And include that file:
assembler.c
#include "parser.h"
int main() {
parse_file("test.txt");
return 0;
}
Or remove the include and provide a clue to the function:
int main() {
void parse_file(char *);
parse_file("test.txt");
return 0;
}
Or even simply remove the include at al. Not good practice, as the compiler (without information on a function) will consider its returned value is an integer and may cause other warnings.
In Unix, I have got three main files. One of them is a library and the other one is a program.
MyLib.c and MyLib.h are the library.
main.c is the program.
In MyLib.h I have a declaration (extern int Variable;). When I try to use Variable in main.c I cannot. Of course I have included MyLib.h in MyLib.c and in main.c, and I link them too. Anyway the variable is not recognized in main.c.
How do I get the variable available when I link the program?
Variable must be defined somewhere. I would declare it as a global variable in MyLib.c, and then only declare it as extern in main.c.
What is happening is that, for both MyLib.c and main.c, the compiler is being told that Variable exists and is an int, but that it's somewhere else (extern). Which is fine, but then it has to actually be somewhere else, and when your linker tries to link all the files together, it can't find Variable actually being anywhere, so it tells you that it doesn't exist.
Try this:
MyLib.c:
int Variable;
MyLib.h:
extern int Variable;
main.c:
#include "MyLib.h"
int main(void)
{
Variable = 10;
printf("%d\n", Variable);
return 0;
}