What happens when including header with static declarations? - c

For example, let's say I have 2 header files.
a.h
#include <stdio.h>
static __inline foo()
{
// do something
}
Then a.h file gets included into b.h:
b.h
#include "a.h"
void bar();
With corresponding b.cpp file:
b.c
#include "b.h"
void bar()
{
foo();
}
main.c
#include "b.h"
void main()
{
bar();
}
Is foo() going to be inlined in b.c file?
Is foo() (static) going to be visible in main.c file since it's included via b.h file or it will be just visible to b.c? (Would guess that it won't be visible since they are not in same translation unit).

foo() is visible in both b and main. The compiler sees the files after the preprocessor has done its job.
main.c after the preprocessor step:
<all the stuff from stdio.h>
static __inline foo()
{
// do something
}
void bar();
void main()
{
bar();
}
One way to remove foo() from main.c is to move inclusion of a.h from b.h to b.c:
Modified b.h:
void bar();
Modified b.c:
#include "a.h"
#include "b.h"
void bar()
{
foo();
}

Is foo() going to be inlined in b.c file?
It is better to say "inlined" into function bar(). Probably it is, but not guaranteed. It is a compiler's decision to inline function or not. Marking function as inline is often just a hint, that may be ignored. Refer to your compiler docs to clarify actual behavior.
Is foo() (static) going to be visible in main.c file since it's
included via b.h file or it will be just visible to b.c? (Would guess
that it won't be visible since they are not in same translation unit).
foo() is visible in every translation unit that includes a.h directly or indirectly. Assuming inlining was ommited, there is another interesting point: each translation unit defines its own copy of foo() i.e. machine code for foo() will be generated for each compiled source. It may be wasteful for non-trivial functions since it leads to bloating of generated code. As consequence you should define static functions in headers only if they are small and are intended to be inlined.

Related

Splitting main file into modules in C

I have three files as such:
module.c:
void bar() {
foo();
}
module.h: (i didn't put the include guard for simplicity)
void bar();
main.c
void foo() {
//some code
}
int main() {
bar();
}
when compiling main.c and module.c, module.c returns an error saying foo() is not defined. How can i fix this up?
Basically, i wanted to take my actual main file, which was pretty large, and split up parts of it to other files for readability, but those functions call other functions found in main
It's tricky because of the directions your dependencies are going.
I can split your code into three compilation units: main.c, module.c, and foo.c
If you do this, you don't have any foo code in main, main only calls bar, and bar includes foo, which is defined in foo.
main.c
#include "module.h"
int main() {
bar();
}
module.c
#include "foo.h"
void bar() {
foo();
}
foo.c
void foo() {
}
Best of all is that you don't need to declare foo outside of foo.h, or bar outside of module.h.
I guess module.h could also define void foo(); thus module.c would implement foo too. On the other hand, if bar depends indirectly on foo, then maybe module.c should include another_module.h implemented by another_module.c.
Put prototype definitions for all your functions into module.h:
int main(int argc,char **argv);
void foo(void);
void bar(void);
int fludger(int abc,char *str);
You get the side benefit that in addition to putting any function in any .c file you wish, you no longer need to order the functions within a given .c file, based upon what calls what [e.g. before if foo called bar, bar would have to be defined above foo]

Linkage and static function confusion

I read that
A function with internal linkage is only visible to one compilation
unit. (...) A function declared static has internal linkage
For .c files it sorta makes sense, but I was wondering what happens with static functions in headers, which get included by multiple .c files but usually have an include guard.
I was reading this answer about static functions in headers, and the first item mentions that it doesn't create a symbol with external linkage and the second item mentions the function is available purely through the header file. Isn't that contradictory? How can the function be available and at the same time have no external symbol? So I did a little test:
/* 1.h */
#ifndef ONE_H
#define ONE_H
#include <stdio.h>
static void foo() {
printf("foo from 1.h %p\n", foo);
return;
}
void bar();
#endif
/* 1.c */
#include "1.h"
#include <stdio.h>
void bar() {
printf("foo,bar from 1.c %p,%p\n", foo, bar);
foo();
}
/* 2.c */
#include "1.h"
#include <stdio.h>
int main() {
printf("foo,bar from main %p,%p\n", foo, bar);
foo();
bar();
return 0;
}
...
debian#pc:~ gcc 2.c 1.c
debian#pc:~ ./a.out
foo,bar from main 0x400506,0x400574
foo from 1.h 0x400506
foo,bar from 1.c 0x400559,0x400574
foo from 1.h 0x400559
As expected bar is the same across all files, but shouldn't foo be too? Isn't 1.h included only once? Adding inline to foo resulted in the same behavior. I'm kinda lost.
Read here, how a header file basically works. That should clarify about your actual question.
Briefly: A header file is just inserted instead of the corresponding #include directive. So any declarations or definitions are treated by the compiler as if you actually copy/pasted the text into your file.
Anyway, you should be careful with function definitions in a header. This is deemed bad style in general. It blows the code for instance, creating redundant copies of that function. Also Function pointers cannot be compared (you never know ...). It is often better to bundle the functions into a library with just the declarations in a header (non-static then: external linkage). There are good justifications sometimes, however (no rule without exceptions). One of them are inline functions.
-static functions are functions that are only visible to other functions in the same file (more precisely the same translation unit).
Check this article for a detailed explanation on linkage: http://publications.gbdirect.co.uk/c_book/chapter4/linkage.html

How to "undeclare" a function prototype or hide a function prototype or #uninclude a header

I would like to have function A() call B() as an inline macro, but I don't want B() to be visible to the world. I only want A() visible and if the user uses B() accidentally, I want a compiler error.
I know how to do it without inlining:
// a.h
void A(void);
// a.c
#include "b.h"
void A(void) { B(); }
If I #include "a.h", then I have access to A() but not B(). That's fine; that's what I want.
Now I want to do the same, but reduce one level of call complexity by inlining B into A, but I want to hide B.
// a.h
#include "b.h"
#define A() B()
#uninclude "b.h" <----This is bogus, but I want the equivalent.
// main.c
#include "a.h"
A(); <-- ok
B(); <-- undefined function
This is for low-level firmware, where the call overhead does make a difference but I don't want to abandon high-level code management just for efficiency. In C++, this is trivial, but I am looking for cpp hacks to do it in pure C.
(In my case, a represents a HAL and b represents a BSP. The HAL is processor specific, while the BSP is board (PCB) specific)
If the only declaration b.h makes is a declaration of B and not a definition, then you can do this in a.h:
// a.h
static inline void A(void)
{
#undef _B__H_ //need this if you have more than one of these inline declarations
#include "b.h"
B();
}
assuming b.h looks like this:
// b.h
#ifndef _B_H_
#define _B_H_
void B(void);
#endif
Then the declaration of B is in scope only within A.
In a.c, be sure to include b.h before a.h (or do #undef _B_H_ to force reloading b.h). Otherwise, you will get warnings or errors about incompatible scopes. (a.h includes b.h at local scope, while a.c includes b.h at file scope then ignores all of the remaining local scope includes.)
This will also work if b.h makes additional declarations, as long as they are acceptable in the scope of a function body.
If you do this:
#define B A
#include "b.h"
#undef B
This changes the definition of B in "b.h" to be a definition of A instead. This requires that b.h define B, not just declare it, so that might not be what you want.
Then after that, in the file where those lines appear, code can use A (with calls such as A()), but no declaration of B is in scope. So attempts to use B would result in compiler errors. (Other declarations made in b.h would be in scope.)
#define A() (B)()
#define B() syntax error
People who write B() will get a syntax error reported (in some shape or form).
People who write A() will generate a call to (B)(), which is OK.
This does not stop someone writing (B)() in the code, of course, but it is 80% of the way there.

Linker error inline function

I got some compiler/linker errors and i don't know what is the correct method to proceed. I'm in this situation:
a.h: in this file is defined a function declared as "inline", for example: inline void foo1();
b.h: in this file is defined a function declared as "inline" that calls foo1(): inline void foo2();
main.c: there are some functions calls of both foo1 and foo2().
Now, if i declare foo1 and foo2 in a.h and b.h as extern inline void i got the following error:
prj/src/b.o: In function foo1': (.text+0x0):
multiple definition offoo1'
prj/src/main.o:(.text+0x0): first defined here make: *
[kernel] Error 1
What is the way which allow to compile and link without errors/warning in the situation i described?
From http://gcc.gnu.org/onlinedocs/gcc/Inline.html:
When an inline function is not static, then the compiler must assume
that there may be calls from other source files; since a global symbol
can be defined only once in any program, the function must not be
defined in the other source files, so the calls therein cannot be
integrated. Therefore, a non-static inline function is always compiled
on its own in the usual fashion.
In other words, without static, it emits a symbol for your inline function. If you happen to define that function in a header and include it in more than one compilation unit, then you end up with multiple (redefined) symbols. If you want to include the definition in the header, you should make it static.
I tried it and didn't get any errors
a.h
extern inline void foo1()
{
return;
}
b.h
extern inline void foo2()
{
foo1();
return;
}
main.cpp
#include "a.h"
#include "b.h"
int main() {
foo1();
foo2();
return 0;
}
Put the inline definitions in your .h file and in the .c files force an external definition.
For example:
// File: a.h
inline void foo1(void) { /*...*/ }
// File main.c
#include "a.h"
extern inline void foo1(void);
int main(void)
{
/*...*/
}
You may consider using header guards to prevent redefinition. The implementation of the files is as follows. I tried compilation for the following files using CMake and it worked without any problem.
a.h
#ifndef A_H
#define A_H
inline
void foo1()
{
return;
}
#endif
b.h
#ifndef B_H
#define B_H
#include "a.h"
inline
void foo2()
{
foo1();
return;
}
#endif
main.cpp
#include "a.h"
#include "b.h"
int main() {
foo1();
foo2();
return 0;
}

Are static functions in C language really invisible?

I was told that a function defined as static in one .c file is not accessible from other files. But in the following program, I can access the static void show() function from another file. Is my understanding of static functions in C wrong?
a.h (first file):
static void show()
{
printf("I am in static show function in a.c");
}
b.c (another file):
#include"a.h"
void main()
{
show();
}
Remember that #includes work by copy-and-pasting the content of the included file. So in your example, after the #include has been processed, you get this:
static void show()
{
printf("I am in static show function in a.c");
}
void main()
{
show();
}
So clearly main can see show.1
The solution is to not #include .c files. In general, you should only #include header (.h) files. Your static functions shouldn't be declared or defined in the header file, so main will not be able to see it.
1. However, you now actually have two definitions of the show function, one in a.c and one in b.c. For static functions, this isn't a problem, but for non-static functions you would get a linker error.
static keyword changes the linkage specification to Internal Linkage.
A function marked as static will only be visible in that Translation Unit(TU).
Perhaps, You have same named symbols available in that particular TU, where you access the function. The how part of it can be only answered after you show us the code.
EDIT:
When you define a static function in header file, A copy of the same function gets created in every Translation Unit where you include it.Each instance of such a function is treated as a separate function(address of each function is different) and each instance of these functions have their own copies of static local variables & string literals.
Clearly, this will work but this might as well increase the size of your generated binary.
The other answers are correct, but it's not quite accurate to say that the static function is not accessible from another file. It is possible to access the function through a function pointer. It would be more accurate to say that the name of the function is not accessible in another translation unit.
Remember that converting C source code to an executable program consists of conceptual stages, including:
preprocessing (in which #include directives are replaced with the contents of the included file
compilation (which processes one translation unit at a time)
linking (in which the translation units are put together into the final program)
Suppose we have three files. foo.h:
typedef void (*void_function_p)(void);
extern void_function_p foo(void);
foo.c:
#include "foo.h"
#include <stdio.h>
static void baz(void) {
printf("worked!\n");
}
void_function_p foo(void) {
return baz;
}
bar.c:
#include "foo.h"
#include <stdio.h>
int main(void) {
(*foo())();
return 0;
}
This program compiles and prints "worked!" when it runs.
There are two translation units here. One is the code in the preprocessed foo.c (which, because of how #include works also includes the code in foo.h and stdio.h). The other is the code in the preprocessed bar.c (which, again, has its own copy of the code in foo.h and stdio.h).
By having the function foo return a pointer to the static function baz, we are able to call baz from the main function.
Now, consider what happens if we modify main to look like this:
int main(void) {
(*foo())();
baz();
return 0;
}
This code will result in a linker error because the name baz in this translation unit cannot be linked to the definition of baz in the other translation unit.
This is the first advantage of static functions: another programmer cannot accidentally access our baz function from another translation unit.
Now, consider what happens if we modify bar.c to look like this:
#include "foo.h"
#include <stdio.h>
static void baz(void) {
printf("still works!");
}
int main() {
(*foo())();
baz();
return 0;
}
This code will compile, and print "worked!" followed by "still works!"
This is the second advantage of static functions: we've defined two functions (in different translation units) with the same name.
If you try to put both static definitions in the same translation unit, you will get a compiler error about defining baz twice.
As a final note, if you take the program as it now stands and remove all the statics, it will result in a linker error because baz has been defined twice (with external linkage), which is not permitted.

Resources