// File: foo.c
static int var;
void foo()
{
var++;
}
// end of file foo.c
// File bar.c:
static int var;
void bar()
{
var++;
}
// end of file bar.c
// file main.c
static int var;
void main()
{
foo();
bar();
printf("%d", var);
}
// end of file main.c
Question: Will the above program compile ? If so what will be the result ?
I tested the code and found it couldn't be compiled. I try to use extern in main.c to use the function foo() and bar() but it still couldn't be compiled.
main.c has a few minor problems - it should be something like this:
#include <stdio.h>
static int var;
extern void foo();
extern void bar();
int main(void)
{
foo();
bar();
printf("%d\n", var);
return 0;
}
It should build OK like this:
$ gcc -Wall main.c foo.c bar.c -o main
and the result should be:
$ ./main
0
I would expect it to compile and print 0 (though if you want to compile it as C++, you'll have to add declarations for foo() and bar(), and in either C or C++, you might get a warning that main() should really return an int).
Since var is defined as static in each of the three files, you really have three separate variables that all happen to have the same name. Perhaps it's easiest to think of each file as defining a struct that contains its static variables. What you've done is called foo(), which increments foo.var. Then you've called bar(), which increments bar.var. Then you've printed out main.var, which was initialized to zero, and never modified.
This compiles for me (although with a warning about the return type from main()).
The result, in terms of what main() will print, is undetermined because you have not initialized the value of var in main.c. The most likely result when the compiler is invoked without optimizations is zero because the OS will have zeroed the physical memory supplied to the process for data storage (the OS does this to avoid leaking confidential data between processes).
The static qualifier to the var variable definitions means that the variable is not visible outside the source file it is defined in. It also means that each of the three var variables gets its own storage location.
If we add a printf("[module name] *var=%p\n", &var) to foo(), bar() and main() respectively to print the address of the memory location that stores those three variables you should get something like this:-
foo() *var=0x8049620
bar() *var=0x8049624
main() *var=0x8049628
Note that each variable gets its own storage location. The code in each source file will access the version of var that is specific to to that source file. Using static like this in .c files is typically used to implement the concept of information hiding in C.
The code (as it is) will compile and result will be 0 (as Jerry explains) because static variable will have file scope.
But, if you include foo.c and bar.c in main.c, and compile as
gcc main.c
then the result will be 2 because there will only be one global variable var.
Related
I am using library that I shouldn't change it files, that including my h file.
the code of the library looks somthing like like:
#include "my_file"
extern void (*some_func)();
void foo()
{
(some_func)();
}
my problem is that I want that some_func will be extern function and not extern pointer to function (I am implementing and linking some_func). and that how main will call it.
that way I will save little run time and code space, and no one in mistake will change this global.
is it possible?
I thought about adding in my_file.h somthing as
#define *some_func some_func
but it won't compile because asterisk is not allowed in #define.
EDIT
The file is not compiled already, so changes at my_file.h will effect the compilation.
First of all, you say that you can't change the source of the library. Well, this is bad, and some "betrayal" is necessary.
My approach is to let the declaration of the pointer some_func as is, a non-constant writable variable, but to implement it as constant non-writable variable, which will be initialized once for all with the wanted address.
Here comes the minimal, reproducible example.
The library is implemented as you show us:
// lib.c
#include "my_file"
extern void (*some_func)();
void foo()
{
(some_func)();
}
Since you have this include file in the library's source, I provide one. But it is empty.
// my_file
I use a header file that declares the public API of the library. This file still has the writable declaration of the pointer, so that offenders believe they can change it.
// lib.h
extern void (*some_func)();
void foo();
I separated an offending module to try the impossible. It has a header file and an implementation file. In the source the erroneous assignment is marked, already revealing what will happen.
// offender.h
void offend(void);
// offender.c
#include <stdio.h>
#include "lib.h"
#include "offender.h"
static void other_func()
{
puts("other_func");
}
void offend(void)
{
some_func = other_func; // the assignment gives a run-time error
}
The test program consists of this little source. To avoid compiler errors, the declaration has to be attributed as const. Here, where we are including the declarating header file, we can use some preprocessor magic.
// main.c
#include <stdio.h>
#define some_func const some_func
#include "lib.h"
#undef some_func
#include "offender.h"
static void my_func()
{
puts("my_func");
}
void (* const some_func)() = my_func;
int main(void)
{
foo();
offend();
foo();
return 0;
}
The trick is, that the compiler places the pointer variable in the read-only section of the executable. The const attribute is just used by the compiler and is not stored in the intermediate object files, and the linker happily resolves all references. Any write access to the variable will generate a runtime error.
Now all of this is compiled in an executable, I used GCC on Windows. I did not bother to create a separated library, because it doesn't make a difference for the effect.
gcc -Wall -Wextra -g main.c offender.c lib.c -o test.exe
If I run the executable in "cmd", it just prints "my_func". Apparently the second call of foo() is never executed. The ERRORLEVEL is -1073741819, which is 0xC0000005. Looking up this code gives the meaning "STATUS_ACCESS_VIOLATION", on other systems known as "segmentation fault".
Because I deliberately compiled with the debugging flag -g, I can use the debugger to examine more deeply.
d:\tmp\StackOverflow\103> gdb -q test.exe
Reading symbols from test.exe...done.
(gdb) r
Starting program: d:\tmp\StackOverflow\103\test.exe
[New Thread 12696.0x1f00]
[New Thread 12696.0x15d8]
my_func
Thread 1 received signal SIGSEGV, Segmentation fault.
0x00000000004015c9 in offend () at offender.c:16
16 some_func = other_func;
Alright, as I intended, the assignment is blocked. However, the reaction of the system is quite harsh.
Unfortunately we cannot get a compile-time or link-time error. This is because of the design of the library, which is fixed, as you say.
You could look at the ifunc attribute if you are using GCC or related. It should patch a small trampoline at load time. So when calling the function, the trampoline is called with a known static address and then inside the trampoline there is a jump instruction that was patched with the real address. So when running, all jump locations are directly in the code, which should be efficient with the instruction cache. Note that it might even be more efficient than this, but at most as bad as calling the function pointer. Here is how you would implement it:
extern void (*some_func)(void); // defined in the header you do not have control about
void some_func_resolved(void) __attribute__((ifunc("resolve_some_func")));
static void (*resolve_some_func(void)) (void)
{
return some_func;
}
// call some_func_resolved instead now
This question already has answers here:
What is a "static" function in C?
(11 answers)
Closed 2 years ago.
What's the difference between the following scenarios?
// some_file.c
#include "some_file.h" // doesn't declare some_func
int some_func(int i) {
return i * 5;
}
// ...
and
// some_file.c
#include "some_file.h" // doesn't declare some_func
static int some_func(int i) {
return i * 5;
}
// ...
If all static does to functions is restrict their accessibility to their file, then don't both scenarios mean some_func(int i) can only be accessed from some_file.c since in neither scenario is some_func(int i) put in a header file?
A static function is "local" to the .c file where it is declared in. So you can have another function (static or nor) in another .c file without having a name collision.
If you have a non static function in a .c file that is not declared in any header file, you cannot call this function from another .c file, but you also cannot have another function with the same name in another .c file because this would cause a name collision.
Conclusion: all purely local functions (functions that are only used inside a .c function such as local helper functions) should be declared static in order to prevent the pollution of the name space.
Example of correct usage:
file1.c
static void LocalHelper()
{
}
...
file2.c
static void LocalHelper()
{
}
...
Example of semi correct usage
file1.c
static LocalHelper() // function is local to file1.c
{
}
...
file2.c
void LocalHelper() // global functio
{
}
...
file3.c
void Foo()
{
LocalHelper(); // will call LocalHelper from file2.c
}
...
In this case the program will link correctly, even if LocalHelpershould have been static in file2.c
Example of incorrect usage
file1.c
LocalHelper() // global function
{
}
...
file2.c
void LocalHelper() // global function
{
}
...
file3.c
void Foo()
{
LocalHelper(); // which LocalHelper should be called?
}
...
In this last case we hava a nema collition and the program wil not even link.
The difference is that with a non-static function it can still be declared in some other translation unit (header files are irrelevant to this point) and called. A static function is simply not visible from any other translation unit.
It is even legal to declare a function inside another function:
foo.c:
void foo()
{
void bar();
bar();
}
bar.c:
void bar()
{ ... }
What's the difference between declaring a function static and not including it in a header?
Read more about the C programming language (e.g. Modern C), the C11 standard n1570. Read also about linkers and loaders.
On POSIX systems, notably Linux, read about dlopen(3), dlsym(3), etc...
Practically speaking:
If you declare a function static it stays invisible to other translation units (concretely your *.c source files, with the way you compile them: you could -at least in principle, even if it is confusing- compile foo.c twice with GCC on Linux: once as gcc -c -O -DOPTION=1 foo.c -o foo1.o and another time with gcc -c -O -DOPTION=2 -DWITHOUT_MAIN foo.c -o foo2.o and in some cases be able to link both foo1.o and foo2.o object files into a single executable foo using gcc foo1.o foo2.o -o foo)
If you don't declare it static, you could (even if it is poor taste) code in some other translation unit something like:
if (x > 2) {
extern int some_func(int); // extern is here for readability
return some_func(x);
}
In practice, I have the habit of naming all my C functions (including static ones) with a unique name, and I generally have a naming convention related to them (e.g. naming them with a common prefix, like GTK does). This makes debugging the program (with GDB) easier (since GDB has autocompletion function names).
At last, a good optimizing compiler could, and practically would often, inline calls to static functions whose body is known. With a recent GCC, compile your code with gcc -O2 -Wall. If you want to check how inlining happened, look into the produced assembler (using gcc -O2 -S -fverbose-asm).
On Linux, you can obtain using dlsym the address of a function which is not declared static.
We can declare weak function by using __attribute__((weak)) in C code files. I wonder if there exists a way to declare this during compile time from gcc and not write anything in the code files?
For e.g.
File: foo.h
int foo();
File: foo.c
#include<stdio.h>
int foo(){
printf("foo called from file\n");
return 1;
}
File: main.c
#include<stdio.h>
#include"foo.h"
int foo(){
printf("foo called from main");
return 1;
}
int main(){
foo();
return 0;
}
Is it possible to compile above code and export foo as weak from command line?
E.g. gcc --weak=foo.c:foo foo.c main.c
./a.out produces foo called from main.
I know that writing__attribute__((weak)) above foo() declaration in foo.c will call foo() in main.
The blog:
blog.microjoe.org/2017/unit-tests-c-cmocka-coverage-cmake.html
says that it is possible to do so....
There are two ways of declaring a weak symbol:
By passing an argument to GCC, telling it to export the symbol of this function as a weak symbol.
By putting a attribute((weak)) annotation before the function implementation.
I would say no, there is no such option.
This sounds a little bit like an XY-problem, perhaps you should state more clearly what problem you are trying to solve, instead of which solution you want to make work.
As an aside, your example would not work, since you're providing two definitions and not saying which one should be considered weak. It would have to be
# Remember this doesn't really work!
$ gcc --weak=foo.c:foo foo.c main.c
or something, i.e. you need to indicate in which file the weak definition resides.
I wrote the following 3 C source files to test the extern keyword
in C :
main.c
#include<stdio.h>
extern int var;
int main()
{
var = 10;
printf("%d %p",var,&var);
var = 20;
}
main2.c
#include<stdio.h>
extern int var;
int main()
{
printf("%d %p",var,&var);
}
other.c
int var;
I compiled the two files main.c and main2.c separately but also linking
the other.c file with each
On running the first program i got the following output :
10 0x8049660
But on running the second after that i got this :
0 0x8049660
It is evident that the two var's point to the same address which is the
point of using the extern keyword.
But why does it again get initialized to 0 ?
Also if I run the second program without running the first I get
the same output.
Why is it so ?
Keyword extern is not for sharing variables among different programs or even not among consecutive runs of the same program. A variable declared as extern just means that this variable is defined in another translation unit of the same program, and the value of this variable will be shared only in this program run.
Note that other.c and main.c are two translation units that get linked to the same program, let's say main.exe. Within one run of main.exe, the value of var will be shared among other.c and main.c, and the address will be the same. For a second run of main.exe, you may receive different addresses, i.e. a different value for &var compared to that of the first run.
I have these two different program where I want to access the static variable declared in program1 from program2.
Program1. (
/* file a.c */)
#include<stdio.h>
static int a = 100; /* global static variable not visible outside this file.*/
int *b = &a; /* global int pointer, pointing to global static*/
Program2
#include<stdio.h>
/* file b.c */
extern int *b; /* only declaration, b is defined in other file.*/
int main()
{
printf("%d\n",*b); /* dereferencing b will give the value of variable a in file a.c */
return 0;
}
While I compile program1 , gcc a.c , no compilation error, but while I compile program2 ( gcc b.c) I am getting compilation error .
test_b.c:(.text+0x7): undefined reference to `b'
collect2: error: ld returned 1 exit status
Why there is compile error ? Here is the link of program static
Thanks in advance.
EDIT 1:
My intention to use static variable from other program. I thought every .c program must have main() function and only .h program have declaration , I am wrong at that point. So I remove main() function from a.c program and instead of compiling two different program separately , now I compile only once using gcc a.c b.c as per suggestion of Filip. Now it's working fine. Thanks all of you.
You have to link against a.c while compiling b.c:
gcc a.c b.c
You can't expect the linker to magically find the C file where b is defined. extern means it is defined elsewhere - you have to say where. By compiling and linking with a.c, the linker can now find a declaration for b.
Of course, you can't have 2 main() functions.
Well, your code already said it. b.cpp only has a declaration, not a definition, of the symbol in question.
Since these are clearly meant to be source files from two separate projects, I would suggest moving your definition to its own .cpp file which may then be shared between the two projects.
$ gcc a.c myIntPointerIsHere.c
$ gcc b.c myIntPointerIsHere.c
However, there are clearer ways to share code between two different projects.
The both modules contain the definition of main. It seems that the compiler did not include the first module in your project. Otherwise I think it would issue an error that main was redefined.