gcc 4.4.2 c89
I am have been re-engineering some one else's source code.
In a function someone has declared some static variables, but doesn't seem to serve any purpose of having them static. I am just wondering if my comment below would be accurate?
static char tempstr[64];
For my understanding when declaring static variables inside a function it will retain is scope so acts like a global variable.
Also, if the static variable is declared in global scope, then its scope is limited to the file only.
Many thanks for any suggestions,
If I understand your interpretation, it is accurate.
Inside a function static means "allocate data segment memory so the value persists between function calls and so that all function instances (think, recursion or threads) share the same actual storage."
This matters a lot if a previous value is used in a later function call or if a reference is leaked out of the function by an external call or by returning a pointer.
Yes, your interpretation is correct. Except that be careful with what you call "acts like a global". It acts like a global only in the sense that it retains values between calls, but it's not globally visible, but still only in the function that declared it.
Also see this question.
It doesn't make it a global. Its still a local variable it just retains its value during successive calls.
That's correct. One more aspect to keep in mind is that if your code is multi-threaded, all the threads will share the same copy of the variable, so it is technically possible that the original designer used that variable as a cross-thread communication mechanism. I don't advocate that technique, but I can't rule it out without more information.
Related
There might be another question like this on stack but I am not completely sure. So on to my question. My professor told everyone, "NEVER USE GLOBAL VARIABLES". But she said that static variables are allowed as long as you give a good enough reason. So my question is, under her criteria, is a static variable declared at the global level ok?
Unfortunately static has two meanings in C. When applied to a global variable, it means that the visibility of this symbol is in the file scope. When applied to a local variable, it means that this variable retains its value between calls (i.e., it's not really a local variable). Your professor is referring to the latter, not the former, when she says they are allowed.
There are times when global variables are useful. Consider stderr: it would be a pain to have to define it in every file you needed to use it in; it is sensibly defined as a global variable.
There are times when it is sensible to store a variable at file scope without external linkage (which you do using static as part of the definition of the variable, outside the scope of any function). For example, if you have a suite of functions which need to share some state but the API does not pass a handle back to the calling code (so there isn't an analogue of open and close — or create and destroy), then one or more static variables at file scope make sense.
C89
gcc (GCC) 4.7.2
Hello,
I am maintaining someones software and I found this function that returns the address of a static structure. This should be ok as the static would indicate that it is a global so the address of the structure will be available until the program terminates.
DRIVER_API(driver_t*) driver_instance_get(void)
{
static struct tag_driver driver = {
/* Elements initialized here */
};
return &driver;
}
Used like this:
driver_t *driver = NULL;
driver = driver_instance_get();
The driver variable is used throughout the program until it terminates.
some questions:
Is it good practice to do like this?
Is there any difference to declaring it static outside the function at file level?
Why not pass it a memory pool into the function and allocate memory to the structure so that the structure is declared on the heap?
Many thanks for any suggestions,
Generally, no. It makes the function non-reentrable. It can be used with restraint in situations when the code author really knows what they are doing.
Declaring it outside would pollute the file-level namespace with the struct object's name. Since direct access to the the object is not needed anywhere else, it makes more sense to declare it inside the function. There's no other difference.
Allocate on the heap? Performance would suffer. Memory fragmentation would occur. And the caller will be burdened with the task of explicitly freeing the memory. Forcing the user to use dynamic memory when it can be avoided is generally not a good practice.
A better idea for a reentrable implementation would be to pass a pointer to the destination struct from the outside. That way the caller has the full freedom of allocating the recipient memory in any way they see fit.
Of course, what you see here can simply be a C implementation of a singleton-like idiom (and most likely it is, judging by the function's name). This means that the function is supposed to return the same pointer every time, i.e. all callers are supposed to see and share the same struct object through the returned pointer. And, possibly, thy might even expect to modify the same object (assuming no concurrency). In that case what you see here is a function-wrapped implementation of a global variable. So, changing anything here in that case would actually defeat the purpose.
As long as you realize that any code that modifies the pointer returned by the function is modifying the same variable as any other code that got the same pointer is referring to, it isn't a huge problem. That 'as long as' can be a fairly important issue, but it works. It usually isn't the best practice — for example, the C functions such as asctime() that return a pointer to a single static variable are not as easy to use as those that put their result into a user-provided variable — especially in threaded code (the function is not reentrant). However, in this context, it looks like you're achieving a Singleton Pattern; you probably only want one copy of 'the driver', so it looks reasonable to me — but we'd need a lot more information about the use cases before pontificating 'this is diabolically wrong'.
There's not really much difference between a function static and a file static variable here. The difference is in the implementation code (a file static variable can be accessed by any code in the file; the function static variable can only be accessed in the one function) and not in the consumer code.
'Memory pool' is not a standard C concept. It would probably be better, in general, to pass in the structure to be initialized by the called function, but it depends on context. As it stands, for the purpose for which it appears to be designed, it is OK.
NB: The code would be better written as:
driver_t *driver = driver_instance_get();
The optimizer will probably optimize the code to that anyway, but there's no point in assigning NULL and then reassigning immediately.
New EE with very little software experience here.
Have read many questions on this site over the last couple years, this would be my first question/post.
Haven't quite found the answer for this one.
I would like to know the difference/motivation between having a function modify a global variable within the body (not passing it as a parameter), and between passing the address of a variable.
Here is an example of each to make it more clear.
Let's say that I'm declaring some functions "peripheral.c" (with their proper prototypes in "peripheral.h", and using them in "implementation.c"
Method 1:
//peripheral.c
//macros, includes, etc
void function(*x){
//modify x
}
.
//implementation.c
#include "peripheral.h"
static uint8 var;
function(&var); //this will end up modifying var
Method 2:
//peripheral.c
//macros, includes, etc
void function(void){
//modify x
}
.
//implementation.c
#include "peripheral.h"
static uint8 x;
function(); //this will modify x
Is the only motivation to avoid using a "global" variable?
(Also, is it really global if it just has file scope?)
Hopefully that question makes sense.
Thanks
The function that receives a parameter pointing to the variable is more general. It can be used to modify a global, a local or indeed any variable. The function that modifies the global can do that task and that task only.
Which is to be preferred depends entirely on the context. Sometimes one approach is better, sometimes the other. It's not possible to say definitively that one approach is always better than the other.
As for whether your global variable really is global, it is global in the sense that there is one single instance of that variable in your process.
static variables have internal linkage, they cannot be accessed beyond the translation unit in which they reside.
So if you want to modify a static global variable in another TU it will be have to be passed as an pointer through function parameter as in first example.
Your second example cannot work because x cannot be accessed outside implementation.c, it should give you an compilation error.
Good Read:
What is external linkage and internal linkage?
First of all, in C/C++, "global" does mean file scope (although if you declare a global in a header, then it is included in files that #include that header).
Using pointers as parameters is useful when the calling function has some data that the called function should modify, such as in your examples. Pointers as parameters are especially useful when the function that is modifying its input does not know exactly what it is modifying. For example:
scanf("%d", &foo);
scanf is not going to know anything about foo, and you cannot modify its source code to give it knowledge of foo. However, scanf takes pointers to variables, which allows it to modify the value of any arbitrary variable (of types it supports, of course). This makes it more reusable than something that relies on global variables.
In your code, you should generally prefer to use pointers to variables. However, if you notice that you are passing the same chunk of information around to many functions, a global variable may make sense. That is, you should prefer
int g_state;
int foo(int x, int y);
int bar(int x, int y);
void foobar(void);
...
to
int foo(int x, int y, int state);
int bar(int x, int y, int state);
void foobar(int state);
...
Basically, use globals for values that should be shared by everything in the file they are in (or files, if you declare the global in a header). Use pointers as parameters for values that should be passed between a smaller group of functions for sharing and for situations where there may be more than one variable you wish to do the same operations to.
EDIT: Also, as a note for the future, when you say "pointer to function", people are going to assume that you mean a pointer that points to a function, rather than passing a pointer as a parameter to a function. "pointer as parameter" makes more sense for what you're asking here.
Several different issues here:
In general, "global variables are bad". Don't use them, if you can avoid it. Yes, it preferable to pass a pointer to a variable so a function can modify it, than to make it global so the function can implicitly modify it.
Having said that, global variables can be useful: by all means use them as appropriate.
And yes, "global" can mean "between functions" (within a module) as well as "between modules" (global throughout the entire program).
There are several interesting things to note about your code:
a) Most variables are allocated from the "stack". When you declare a variable outside of a function like this, it's allocated from "block storage" - the space exists for the lifetime of the program.
b) When you declare it "static", you "hide" it from other modules: the name is not visible outside of the module.
c) If you wanted a truly global variable, you would not use the keyword "static". And you might declare it "extern uint8 var" in a header file (so all modules would have the definition).
I'm not sure your second example really works, since you declared x as static (and thus limiting its scope to a file) but other then that, there are some advantages of the pointer passing version:
It gives you more flexibility on allocation and modularity. While you can only have only one copy of a global variable in a file, you can have as many pointers as you want and they can point to objects created at many different places (static arrays, malloc, stack variables...)
Global variables are forced into every function so you must be always aware that someone might want to modify them. On the other hands, pointers can only be accessed by functions you explicitely pass them to.
In addition to the last point, global variables all use the same scope and it can get cluttered with too many variables. On the other hand, pointers have lexical scoping like normal varialbes and their scope is much more restricted.
And yes, things can get somewhat blurry if you have a small, self contained file. If you aren't going to ever instantiate more then one "object" then sometimes static global variables (that are local to a single file) work just as well as pointers to a struct.
The main problem with global variables is that they promote what's known as "tight coupling" between functions or modules. In your second design, the peripheral module is aware of and dependent on the design of implementation, to the point that if you change implementation by removing or renaming x, you'll break peripheral, even without touching any its code. You also make it impossible to re-use peripheral independently of the implementation module.
Similarly, this design means function in peripheral can only ever deal with a single instance of x, whatever x represents.
Ideally, a function and its caller should communicate exclusively through parameters, return values, and exceptions (where appropriate). If you need to maintain state between calls, use a writable parameter to store that state, rather than relying on a global.
I have a choice to between declaring a variable static or global.
I want to use the variable in one function to maintain counter.
for example
void count()
{
static int a=0;
for(i=0;i<7;i++)
{
a++;
}
}
My other choice is to declare the variable a as global.
I will only use it in this function count().
Which way is the safest solution?
It matters only at compile and link-time. A static local variable should be stored and initialised in exactly the same way as a global one.
Declaring a local static variable only affects its visibility at the language level, making it visible only in the enclosing function, though with a global lifetime.
A global variable (or any object in general) not marked static has external linkage and the linker will consider the symbol when merging each of the object files.
A global variable marked static only has internal linkage within the current translation unit, and the linker will not see such a symbol when merging the individual translation units.
The internal static is probably better from a code-readability point of view, if you'll only ever use it inside that function.
If it was global, some other function could potentially modify it, which could be dangerous.
Either using global or static variable within a function both are not safe because then your function will no longer be re-entrant.
However if you are not concerned with function being re-entrant then you can have either based on your choice.
If the variable is only to be accessed within the function count() then it is by definition local, so I cannot see why the question arises. As a rule, always use the most restrictive scope possible for any symbol.
You should really read Jack Ganssle's article A Pox on Globals, it will be enlightening.
Always reduce scope as far as possible. If a variable doesn't need to be visible outside a function, it should not be declared outside it either. The static keyword should be used whenever possible. If you declare a variable at file scope, it should always be static to reduce the scope to the file it was declared in. This is C's way of private encapsulation.
The above is true for all systems. For embedded there is another concern: all variables declared as static or global must be initialized before the program is started. This is enforced by ISO C. So they are always set either to the value the programmer wants them initialized to. If the programmer didn't set any value they are initialized to zero (or NULL).
This means that before main is called, there must be a snippet executed in your program that sets all these static/global values. In an embedded system, the initialization values are copied from ROM (flash, eeprom etc) to RAM. A standard C compiler handles this by creating this snippet and adding it to your program.
However, in embedded systems this snippet is often unfortunate, as it leads to a delay at program startup, especially if there is lots of statics/globals. A common non-standard optimization most embedded compilers support, is to remove this snippet. The program will then no longer behave as expected by the C standard, but it will be faster. Once you have done this optimization, initialization must be done in runtime, roughly static int x; x=0; rather than static int x=0;.
To make your program portable to such non-standard embedded compilers, it is a good habit to always set your globals/statics in runtime. And no matter if you intend to port to such compilers or not, it is certainly a good habit not to rely on the default zero initialization of globals/statics. Because most rookie C programmers don't even know that this static zero initialization rule exists and they will get very confused if you don't init your variables explicitly before using them.
i dont think is there is anything special with static & normal global with embedded domain ...!!
in one way static is good that if you are going to initialize your counter as o in starting then if you just declare with static then there is no need to initialize with it 0 because every static varaible is by default initialized with 0.
Edit :
After Clifford's comment i have checked and get to know that globals are also statically allocated and initialised to zero, so that advantage does not exist..
Pass a pointer to a "standard" variable instead
void count(int *a) {
int i;
for (i = 0; i < 7; i++)
{
(*a)++;
}
}
This way you do not rely neither on global variables nor on static local variables, which makes your program better.
I would say static is better than global if you want only one function to access it in which you declared it . Plus global variables are more prone to be accidentally accessed by other functions.
If you do want to use globals since it can be accessed by other functions in the program, make sure you declare them as volatile .
volatile int a = 0;
volatile makes sure it is not optimised by compilers in the wrong way.
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.