I've a newbie question about how to correctly move an interrupt handler to an include file. I've a SysTick handler in my main.c file defined in this way:
volatile int systick_timer_counter = 0;
void SysTick_Handler(void) {
systick_timer_counter++;
}
I use this systick_timer_counter, that is increased every 10 ms, to trigger some checks after some time has passed, then reset it.
What I want is to use this systick_timer_counter also inside some functions that aren't in my main.c file, but in another function's .c file. So I want to create a file called systick_counter to include where I need to use it.
What I'm asking is, how should I do this in correct way? I can just create a .c file and place variable and interrupt header inside it, or should I add something more or change variable definition?
It sounds like you mean you want to have a global variable defined in
one module (source file) that’s accessible from other modules.
Assuming I’ve interpreted your question correctly, yes, that can be done
by using the extern keyword. However, it would be irresponsible of me
not to say that using globals unnecessarily is bad practice. It
results in hard-to-maintain code, because an extern global might be
changed from anywhere in the code base. You want to limit scope and
visibility of your identifiers as much as you can.
In this instance, I would recommend that you instead keep
systick_timer_counter local to the module in which it’s defined, and
use functions in that module to access it. It’s like defining a class
with methods, in a language that doesn’t have explicit classes. Doing it
this way, other modules can’t change the value except by calling
reset_systick().
int systick_timer_counter = 0;
void reset_systick()
{
systick_timer_counter = 0;
}
void SysTick_Handler()
{
systick_timer_counter++;
}
int return_systick()
{
return systick_timer_counter;
}
It's also a good idea to add the static keyword to variables that you want to only be accessible from within the file.
static int systick_timer_counter = 0;
Related
Say we have a library that defines the following internally used function skip_comments, that is used only by the translation unit it is defined in
void skip_comments(...)
{
}
void another_function()
{
skip_comments(...) //calls the above function --- (1)
}
Now this library is used by another process which also has a function with the same name skip_comments.
This will cause a function name conflict between the library function vs the function defined in the process. So at the point (1) I might expect it to call the process's function instead of the library function which clearly is a bug.
As a possible fix, I made the skip_comment function static and now the bug seems to be fixed. But I'm not sure if this is a proper fix
My question is, would defining the skip_comment as static ensure that at (1) such a name conflict will not occur? ie.
static void skip_comments(...)
{
}
void another_function()
{
skip_comments(...) // will it always call the internal function?
}
Or the only solution is to make sure we define a unique name for functions such as adding prefixes?
Declaring a function as static means that it will only be accessible by the translation unit where it is declared. (Translation unit meaning the .c file and all .h files included by that .c file.)
So yes, declaring it as static will solve your name conflicts. Given that you do this consistently everywhere and not just in one file.
However, it is good practice to prefix all identifiers based on the module where they belong, so that is perhaps the best solution regardless.
I am making a low level library that requires initialization to work properly which I implemented with a init function. I am wondering if there is a way to make the init call be called once the user calls a library function ideally without:
Any overhead
No repeated calls
No exposed global variables. (my current solution does this, which I don't quite like)
my current solution as per comment request:
bool isinit = 0;
void init()
{
isinit = 1;
// init code
}
void lib_function()
{
if(!isinit) init();
// function code
}
The compiler seems to be smart enough (using -0fast on gcc) to not make that comparison each time a lib_function is called, but this still exposes a global variable which I don't like.
Best way to abstract away an init function?
Surely your library has some state. Typically, a library exposes functions that work on a specific structure. Do not use global variables - do not write spaghetti code. Expose the structure that holds the state of your library, and make all functions of your library take a pointer to the structure as an argument. Use a namespace - prepend all exported symbols with a prefix. An init function is just like int lib_init(struct lib_the_struct *t); - it will be self-understandable that users need to initialize the structure with that function before use. For example: fopen(), pthread_create.
Write an init function in your library. Write clear documentation stating, that the user of your library has to call the function once before calling any other function. For example: https://curl.se/libcurl/c/curl_global_init.html .
If you're happy with a solution that is a common extension rather than part of the C standard, you can mark your init function with the constructor attribute, which ensures it will be called automatically during program initialization (or during shared library load if you eventually end up using that).
I would fix this with assert so that the if will dissappear in release build and if you forget to call the init_function somewhere you get the error while developing.
Also turn isinit into a static so every library can have its own variable with the same name.
#include <assert.h>
#ifndef NDEBUG
static int isinit = 0;
#endif
void lib_function()
{
assert(isinit && "library: init not called");
}
There will be overhead if you run if(!isinit) init(); each time you call a function. At least an extra branch.
As for removing global variables, do in your example but static bool isinit = 0;. This reduces the scope of the variable to the local translation unit (.c file and all .h files it includes). It's no longer "global". Note that this isn't ideal in multi-threaded scenarios - you will have to protect the variable with a mutex then.
Overall though, what you are trying to do isn't a good idea. It is very common convention for C libraries to have an init function and the user of the library is expected to call it before calling anything else or they are to blame, not your library. Naturally you have to make this clear to them with source code documentation. It is common to have a list of prerequisites in source code comments together with every function declaration placed in the header file of the library.
What are the differences between static and external variables? What are the advantages of making a static variable?
Why do we prefer making external variables in multifunction programs? The book says that else it gets initialized very late. I don't get it.
Problem is that in C static can have different meanings. I will try to give an overview of the different situations in the following paragraphs.
If a variable is defined outside a function, it can be used by all functions in the file. Sometimes also called 'global variable'. This means that there is only one instance of this variable for the whole file. Also the name of the variable is stored in the resulting .OBJ file. This latter is important, since if another file also defines a variable with the same name outside a function, the linker assumes that it's the same variable in both cases, and merges them.
To make this extra clear, it's best to add the keyword "extern" to one of the variables. In this case, we say that we declare the variable, instead of defining it. It is an extra signal for the compiler/linker to indicate that we actually want to refer to a global variable defined somewhere else.
If you want to define a global variable, but don't want to make it available to other files, add the keyword static before. The keyword static tells the compiler that the variable name must not be stored in the .OBJ file. This means that two .C files with the following line:
static long MyGlobalVariable;
will each have their own variable. Both variables will be called MyGlobalVariable.
If you define a variable inside a function, it becomes a local variable. It comes into existence if the function is called, and disappears again after the function is finished.
In some situations you want to keep the value of the variable in between function calls. You could do this by using a global variable (instead of a local variable) but then the variable becomes available for all functions in the file, which you don't necessarily want. In that case you can put the keyword static before the variable, like this:
void MyFunction()
{
static long MyLocalVariable = 0;
++MyLocalVariable;
}
The first time the function is called, MyLocalVariable will be 'created' and initialized with the value 0. At the end of the function, the variable is not destroyed, but kept. So the next time you call this function, the value of the variable will be 1, not zero.
In C it really doesn't matter whether you put the variable outside the function (as global variable) or define it as static inside the function. The only difference is where the variable can be accessed.
In C++, things are quite different. If you write this (outside a function):
MyClass MyGlobalVariable;
MyGlobalVariable will be constructed (this is: the constructor will be executed) at the start of the application, before even main is called. However, you don't have real control over the order in which all global variables are constructed.
So if another file contains this:
MyOtherClass MySecondGlobalVariable;
You can't know for sure whether MyGlobalVariable or MySecondGlobalVariable is constructed first. This can give problems if the constructor of one of them relies on the presence (construction) of the other one.
On the other hand, if you define the variable as static inside a function:
void MyFunction()
{
static MyClass MyStaticVariable;
}
Then MyStaticVariable will be constructed the first time the function is called. With this construction, you can write something like this:
MyClass &getMyClass()
{
static MyClass MySelf;
return MySelf;
}
And we have implemented a singleton where we have control on when it is constructed. The first time we need it, it's constructed.
To be honest, this approach is a rather simplistic one, because it may lead to problems in multi-threaded applications. In that case, there are other tricks.
"Static" more or less means "this will always exist". Depending on the context, you get different results:
static int global_variable;
void function()
{
static int global_function_variable;
}
class foo
{
static void function()
{
static int foo_function_variable;
//...
}
static int foo_variable;
}
global_variable - Only ever visible within the "translation unit". (Since headers are more or less copied in, does this mean a static global in a header exists as separate variables for all cpp files it's included in?)
global_function_variable is created the first time function is called, and will continue to exist throughout the program's lifetime. The value persists, so if you change it in one function call, the next function call will use the changed variable.
foo::function() is a function that can be called like a global function; you don't need to have an instance of foo to call it. This means it doesn't have a valid this pointer, however. Similarly, foo_variable exists even when there aren't any foo objects. All foo objects have the same foo_variable - if you change it in one object, all other objects "see" the change.
foo_function_variable behaves, I think, just like global_function_variable.
The basic idea behind extern is to control the linkage of a variable:
From MSDN :
// specifying_linkage1.cpp
int i = 1;
void other();
int main() {
// Reference to i, defined above:
extern int i;
}
void other() {
// Address of global i assigned to pointer variable:
static int *external_i = &i;
// i will be redefined; global i no longer visible:
// int i = 16;
}
extern int global_variable;
extern can also be used to link a variable using another language, most commonly, C.
global_variable is the most common usage of extern; it says that elsewhere, there's a variable called "global_variable", and we're going to be using that variable. Somewhere, you need to declare the variable without the extern keyword, or it is never actually created.
How can I declare and define a function so that it is only accessible from a single function? I can declare a function in another function. But since local function definitions are illegal (according to Visual C++) I must define the function at global scope, making it possible for other functions to call it.
void f1() {
void f1_private();
f1priv();
}
void f1_private() {
}
void f2() {
f1_private(); // Legal
}
Is it possible to make f1_private only accessible from f1? If not, what are the uses for locally declared functions?
You can put both functions into a single separate file and make the one you want to be less visible static. A static function in C is only accessible from the same source file in which it was declares (sort of a poor-man's namespace concept).
You then just expose the visible function in your header files as you'd normally do.
The best you can do is to put the two functions in their own file, and declare the "private" one to have static linkage (by prefixing the declaration with the word 'static'). Functions with static linkage are accessible only withing their compilation unit (usually meaning the same file, in most build systems).
If the non-private function has to be called from elsewhere, you would then have to either write its prototype in each file it is called from, or create a header file containing the prototype which is included in each file it is called from.
No.
But you can write in C++, declare method inside class, make method private, and make another class friend of first class.
Put a comment on it.
//For use only by foo.
If someone is really gung-ho about using it, they will find a way despite your best efforts. Even if it means just copying and pasting the code, or refactoring the code. The best thing to do is let them know they shouldn't.
You can also encapsulate it by making it private, if it's in a class. Or static if it isn't.
// at the bottom of your .c file
static void foo()
{
}
void dude()
{
// foo only accessible here, unless you have forward
// declared it higher up in the file
foo();
}
However, note that even static methods can be called outside file scope through a function pointer.
You can declare a separate class, with a public member for one function, and a private member function for the one you want only accessible from the other. If this is only used within a class you can make it an internal class.
I'm refactoring "spaghetti code" C module to work in multitasking (RTOS) environment.
Now, there are very long functions and many unnecessary global variables.
When I try to replace global variables that exists only in one function with locals, I get into dilemma. Every global variable is behave like local "static" - e.g. keep its value even you exit and re-enter to the function.
For multitasking "static" local vars are worst from global. They make the functions non reentered.
There are a way to examine if the function is relay on preserving variable value re-entrancing without tracing all the logical flow?
Short answer: no, there isn't any way to tell automatically whether the function will behave differently according to whether the declaration of a local variable is static or not. You just have to examine the logic of each function that uses globals in the original code.
However, if replacing a global variable with a static local-scope variable means the function is not re-entrant, then it wasn't re-entrant when it was a global, either. So I don't think that changing a global to a static local-scope variable will make your functions any less re-entrant than they were to start with.
Provided that the global really was used only in that scope (which the compiler/linker should confirm when you remove the global), the behaviour should be close to the same. There may or may not be issues over when things are initialized, I can't remember what the standard says: if static initialization occurs in C the same time it does in C++, when execution first reaches the declaration, then you might have changed a concurrency-safe function into a non-concurrency-safe one.
Working out whether a function is safe for re-entrancy also requires looking at the logic. Unless the standard says otherwise (I haven't checked), a function isn't automatically non-re-entrant just because it declares a static variable. But if it uses either a global or a static in any significant way, you can assume that it's non-re-entrant. If there isn't synchronization then assume it's also non-concurrency-safe.
Finally, good luck. Sounds like this code is a long way from where you want it to be...
If your compiler will warn you if a variable is used before initialized, make a suspected variable local without assigning it a value in its declaration.
Any variable that gives a warning cannot be made local without changing other code.
Changing global variables to static local variables will help a little, since the scope for modification has been reduced. However the concurrency issue still remains a problem and you have to work around it with locks around access to those static variables.
But what you want to be doing is pushing the definition of the variable into the highest scope it is used as a local, then pass it as an argument to anything that needs it. This obviously requires alot of work potentially (since it has a cascading effect). You can group similarly needed variables into "context" objects and then pass those around.
See the design pattern Encapsulate Context
If your global vars are truly used only in one function, you're losing nothing by making them into static locals since the fact that they were global anyway made the function that used them non-re-entrant. You gain a little by limiting the scope of the variable.
You should make that change to all globals that are used in only one function, then examine each static local variable to see if it can be made non-static (automatic).
The rule is: if the variable is used in the function before being set, then leave it static.
An example of a variable that can be made automatic local (you would put "int nplus4;" inside the function (you don't need to set it to zero since it's set before use and this should issue a warning if you actually use it before setting it, a useful check):
int nplus4 = 0; // used only in add5
int add5 (int n) {
nplus4 = n + 4; // set
return nplus4 + 1; // use
}
The nplus4 var is set before being used. The following is an example that should be left static by putting "static int nextn = 0;" inside the function:
int nextn = 0; // used only in getn
int getn (void) {
int n = nextn++; // use, then use, then set
return n;
}
Note that it can get tricky, "nextn++" is not setting, it's using and setting since it's equivalent to "nextn = nextn + 1".
One other thing to watch out for: in an RTOS environment, stack space may be more limited than global memory so be careful moving big globals such as "char buffer[10000]" into the functions.
Please give examples of what you call 'global' and 'local' variables
int global_c; // can be used by any other file with 'extern int global_c;'
static int static_c; // cannot be seen or used outside of this file.
int foo(...)
{
int local_c; // cannot be seen or used outside of this function.
}
If you provide some code samples of what you have and what you changed we could better answer the question.
If I understand your question correctly, your concern is that global variables retain their value from one function call to the next. Obviously when you move to using a normal local variable that won't be the case. If you want to know whether or not it is safe to change them I don't think you have any option other than reading and understanding the code. Simply doing a full text search for the the name of the variable in question might be instructive.
If you want a quick and dirty solution that isn't completely safe, you can just change it and see what breaks. I recommend making sure you have a version you can roll back to in source control and setting up some unit tests in advance.