Initialization of variables in embedded applications
There is a variety of reasons why C is so widely favored as a programming language for embedded software. It is a powerful, expressive and efficient language – these are certainly attractions. But another factor is also important: availability of expertise. C is used very widely outside of embedded, so many programmers know the language. Staffing up an embedded software project should, therefore, be quite straightforward.
However, programming for embedded systems, even if it is in a familiar language, is still different from programming a desktop computer …
There are numerous aspects of the use of C that differ in an embedded context. An interesting example is the initialization of variables.
Care should always be taken to ensure that a variable has a sensible initial value. Even if a language specifies that all variables are initially 0, it is bad programming style to not show an explicit initialization. Consider this code:
void my_fun() { int auto_variable = 101; ...
When you declare a variable, you have the option to give it an initial vale. This seems a good idea, but there is a tiny downside. As this variable is automatic, it comes into existence when the function is entered, being allocated space on the stack or in a register. The initialization code is then executed to load the stack location or register with the required value. I believe that it is better to specify this more explicitly, thus:
void my_fun() { int auto_variable;
auto_variable = 101; ...
This makes no difference at all to the executable code. My motivation in suggesting the change is making the code clearer for someone reading/maintaining it later.
So, what about static variables? They should be simpler, as their space is allocated at compile time. Thus, code like this is common:
void my_fun() { static int static_variable = 202; ...
In a desktop computer program, this makes sense. When the program is run, the code and initialized data is read from disk into memory and execution started. However, most embedded systems do not work like that. There is likely to be a copy mechanism that sets up all the initialized variables in RAM from data in Flash. Again, it is my view that this process should be shown more explicitly:
void my_fun() { static int static_variable;
static_variable = 202; ...
This latter example would also apply to variables that are declared outside of functions, which are intrinsically static. Their initialization should be at the site of first use.
Ultimately, in the case of a few C int variables, I am just being picky. But I strongly value clarity in programming style. Always think about the guy who needs to understand/modify/maintain you code sometime in the future. It might even be you!
If we go beyond C and use C++, these same issues occur, but can be much more serious. The initialization of a C++ object is likely to be much more complex that a single assignment.
Comments
Leave a Reply
You must be logged in to post a comment.
The static keyword is missing in your example, isn’t it?
Colin — as oXOx pointed out, I think you forgot to declare “static variable” in “my_fun” as “static”.
Perhaps more importantly IMO, since this variable isn’t automatic (assuming we add the “static” keyword as needed), initializing the variable at declaration is the right way to do it… the way you have it shown, the static int variable will be initialized to 0 in the C startup code (before main()), and then /each/ time we run my_func, the variable will be set/changed to 202.
Barr Group’s Embedded Software Boot Camp (shameless plug, I teach the class) covers this in a section of the class titled “The World Before main()”, which explains all the magic stuff that goes on behind the scenes before main()… we also talk about where different kinds of memory and variables are located and how they’re managed.
I’ve read your blog for many years, long enough to know that you understand how all this works, but I want to make sure that other readers understand this distinction.
@oXOo – You are quite correct! I stupidly omitted the keyword, but that has now been fixed. Thanks for being so observant.
@Dan – Everything you say is true, however, the C language spec does not say precisely what happens “before main()”. Most implementations do work like you say, so your argument is certainly valid. Thanks for the input. The plug is fine as I would want to support anyone who is progressing education in embedded software.
In last example, I think is not quite right, by moving initialise value (202) into second line (static_variable = 202), each time my_fun() is called, this line will executed and static_variable will be re-initialise to 202, losing is previous value.
@Teh – Sorry, but that is incorrect. The initialization is done at compile time for a static variable.
@colin,
Your article seems to be confusing ‘initialisation-of-a-static-storage-variable’ with ‘assignment-to-a-variable’.
What both @dan-smith and @Teh-Kian12-Cheng say in their replies is correct.
Taking a look at your 4th code-snippet, EVERY TIME that “my_fun()” is invoked, the value of 202 will be ASSIGNED to ‘static_variable’.
I am assuming (like your other readers) that this function “my_fun()” will be called more than once during the lifetime of your application.
Why else would you need to declare that particular variable as ‘static’.
[ Unless it is for a different and unrelated reason such as to get the linker to place your “static_variable” somewhere off-the-stack and in a different region of RAM. ]
The extra lines of C-code in the rest of “my_fun()” ( folded behind the ellipsis ) will be making modifications to the value of “static_variable”.
[ If the extra lines don’t modify “static_variable” then why bother with a static-variable at all – just re-factor it into a constant-value. ]
If we adopt your proposal and re-factor all code that looks like the 3rd code-snippet into the structure of the 4th code-snippet, then it will actually change the functional operation of the application.
The 3rd and 4th code-snippets are NOT functionally equivalent, in each-and-every circumstance.
The difference between the 2 snippets is :
* in the 4th-snippet, the effects of the extra lines that modify “static_variable” will be lost on the next invocation of “my_fun()”
* in the 3rd-snippet the effects of the extra lines will be preserved.
A simple test-case written in C and compiled with a standards-compliant compiler shows this to be true :
/**
*
* test_case1.c
*
* Purpose:
* Validate operation of static-variable initialisation.
*
* Build instructions:
* gcc -std=c11 -o test_case1 test_case1.c
* OR
* gcc -std=c90 -o test_case1 test_case1.c
*
* Generates the following output:
* var1 = 12345
* var1 = 24690
* var1 = 49380
* var2 = 12345
* var2 = 12345
* var2 = 12345
**/
#include
void snippet3_my_func()
{
static int var1 = 12345; // initialisation
printf("var1 = %d\n", var1);
var1 = var1 * 2;
}
void snippet4_my_func()
{
static int var2;
var2 = 12345; // assignment
printf("var2 = %d\n", var2);
var2 = var2 * 2;
}
int main(int argc, char* argv[])
{
snippet3_my_func();
snippet3_my_func();
snippet3_my_func();
snippet4_my_func();
snippet4_my_func();
snippet4_my_func();
}
@Steven
>> Taking a look at your 4th code-snippet, EVERY TIME that “my_fun()” is invoked, the value of 202 will be ASSIGNED to ‘static_variable’.
Exactly. The 3rd snippet looks like that would be the case, to the casual reader, but would not function that way, which is confusing.
>> I am assuming (like your other readers) that this function “my_fun()” will be called more than once during the lifetime of your application.
>> Why else would you need to declare that particular variable as ‘static’.
There are reasons why you might make the variable static apart from preserving its value from one call to another. For example, a pointer might exist to this variable giving access to it when it’s out of scope. [I did not say this is a good idea, BTW.]
@Colin,
I have a few comments on your reply dated 29-Aug.
( You-wrote )
> Exactly. The 3rd snippet looks like that would be the case, to the casual reader,
> but would not function that way. which is confusing
No, that is definitely NOT the case.
For anyone who is competent with the C-programming-language there is ZERO confusion about how that 3rd-snippet works.
The 3rd-snippet is the simplest example that demonstrates how initialization-of-a-static-storage-variable operates and there is ZERO ambiguity there.
The semantics of how a ‘static-storage-variable’ operates is a fundamental aspect of the C-programming-language and would be taught on day-one of any training course on C-programming.
For anyone who needs clarification, then they would do well to look at their own copy of Kernighan and Ritchie’s ‘The C Programming Language’.
In particular section 4.6 Static Variables, section 4.9 Initialization, section A 8.7 Initialization.
Or better yet, have them write their own simple test-case in C and then run it, as I did in my last reply to you.
[ By-the-way : your blog appears to have mangled the #include < stdio.h > in my previous code-example. ]
My main objection is that your article is suggesting to your readers that they should re-factor (i.e. change) their own code to switch from the structure of the 3rd-snippet to that of the 4th-snippet.
Your suggestion is dangerous and it is plain-wrong to tell people that they should do this.
BECAUSE THE 3RD-SNIPPET AND 4TH-SNIPPET DO NOT OPERATE THE SAME WAY.
If they follow your advice to re-factor their application, THEY WILL INTRODUCE A BUG INTO THEIR SRC-CODE.
Reviewing your final suggestion from your reply dated 29-Aug :
( You-wrote )
> There are reasons why you might make the variable static
> apart from preserving its value from one call to another.
> For example, a pointer might exist to this variable
> giving access to it when it’s out of scope.
> [ I did not say this is a good idea BTW. ]
This is a specious example.
Any programmer who did this would be reprimanded by their supervisor
and told never to do that again.
Your suggestion to access a variable when it is out-of-scope is effectively undefined behaviour of the C-programming-language, and is excluded by the rules laid out in “The-C-language-reference” ISO standards-document.
[ "The C-language-reference : section 6.2.1. Scopes of Identifiers" ]
Clause-2 :
----------
For each different entity that an identifier designates,
the identifier is visible (i.e., can be used)
only within a region of program text called its scope.
....
Clause-4 :
----------
....
If the declarator or type specifier that declares the identifier appears inside a block
or within the list of parameter declarations in a function definition,
the identifier has block scope, which terminates at the end of the associated block.
....
Your suggestion breaks these rules that the Compiler+Optimiser relies on when it generates object-code.
It CANNOT be relied on to work and should not be used in production-quality src-code.
More importantly, there are far better ways of achieving that encapsulation-effect to ‘hide-the-variable’ WHILE still permitting more than one function to access it.
All you would need to do is :
Create a new, empty translation-unit (.c file) and only put in it :
the ‘static-variable’ declared at file-scope-level with a ‘static’ qualifier,
plus all the functions that want to access it.
Better yet, if you really need to control access then make a new, empty translation-unit (.c file) and ONLY put in it the single ‘static-variable’ declared at file-scope with just extern-declared getter and setter functions.
This borrows a code-pattern fundamental to the encapsulation provided by C++ and other Object-Oriented-Languages.
You would get the effect of a PRIVATE static-variable
with all the same operational semantics as any other static-storage-variable
and ONLY permit access to this variable via well-defined PUBLIC getter and setter functions.
@Steven – OK, I take your point. I was trying to make the point that, in an embedded system, the initialization of a static is the result of some code execution. This would have been better illustrated using an external static, which is initialized on entry to main() [which, of course, will only happen once].