I need some explanation/clarification about using local variables in FreeRTOS when I need to pass them to another functions as pointers.
For example I have some function that modifies data under pointer 'data'.
void modify_data(int * data){
*data = 10;
}
Can I use it like this?
void some_function(void){
int d; // local variable
modify_data(&d);
}
Or maybe I should make global variable?
int d;
void some_function(void){
modify_data(&d);
}
Or static variable?
void some_function(void){
static int d;
modify_data(&d);
}
My question in general is:
How to use (or replace) local variables with functions that take pointers in FreeRTOS?
Edit:
At this moment my understanding of this is:
local variables within a function have no use if I want to pass their pointers to another function (or do anything with pointers pointing these variables) because task switching can cause change of memory location where local variable is stored
I have to declare variables as static or global if I want to do anything with their pointers
this is a bit annoying, because a lot of variables in my big program must be declared globally and passing pointers to global data makes no sense except for the readability of the code
I'm using FreeRTOS 10.2.1, CMSIS 1.02 and code runs on STM32 microcontroller.
For starters this statement
*data = (*data)++;
invokes undefined behavior.
As for your question then to change a variable within a function you need to pass it to the function by reference that is indirectly through a pointer to it. For example
void f( int *px )
{
*px = 10;
}
void g( void )
{
static int x;
f( &x );
}
Depends on what you want to do. If you want to use d outside of that function you need to define it as a global, if you are only gonna use it inside the function declare it as local.
So after some discussion in comments and some research I found the answer for my concerns.
Local variables can be used in any way, JUST EXCEPT local variables declared in main function (and in functions called by main) (before FreeRTOS scheduler is started).
Source of my concerns was that I have read in some tutorial, that local functions created in "main context" may be messed up or not exist. It was not explained clearly that it applies to "main c function" and I missunderstood everything thinking that "main context" is context related with Main Stack Pointer, not just "main function".
FAQ on FreeRTOS website says:
The context of main() does not exist after the FreeRTOS scheduler has
started as, from that point, only RTOS tasks and interrupts have a
context. To maximise the amount of RAM available to the FreeRTOS
application, and as allowed by the C standard as the context of main()
no longer exists, some FreeRTOS ports re-use the stack allocated to
main as the system or interrupt stack. Therefore never allocate
variables or buffers that are needed or in any way accessed by the
FreeRTOS application on the stack used by main() because they are
likely to get overwritten.
So this simplified example would be OK:
int x;
int main(void)
{
x = 10;
createTasks();
vTaskStartScheduler();
}
But something like this will not work in FreeRTOS:
int * px; // this pointer will be not valid after vTaskStartScheduler()
int main(void)
{
int x = 10;
px = &x;
createTasks();
vTaskStartScheduler();
}
Someone might ask why I used a local variable in main and want to access it in the rest of the application without declaring it as a global variable. I was doing this because I have developed specyfic/weird way of attaching my code to CMSIS/STM32Cube generated code (which forces the programmer to write in "user code regions") that was working until I started using FreeRTOS.
Related
I have this code that have no idea why it works in online compiler (https://www.programiz.com/c-programming/online-compiler/) (copy this code below and run in that online compiler to verify it).
#include <stdio.h>
void foo(){
static int locl = 0;
locl++;
printf("accessing locl from INSIDE scope: %i\n", locl);
}
int main() {
for (int i=0; i<3; i++){
foo();
printf("accessing locl from OUTSIDE scope: %i\n",*((int *)((unsigned long long)(&foo) + 11979)));
}
return 0;
}
OUTPUT:
accessing locl from INSIDE scope: 1
accessing locl from OUTSIDE scope: 1
accessing locl from INSIDE scope: 2
accessing locl from OUTSIDE scope: 2
accessing locl from INSIDE scope: 3
accessing locl from OUTSIDE scope: 3
So the output is what I expect.
Variable with name locl is static integer that will increment 1 every time foo is called, but focus on this part when I tried accessing static local variable outside its scope:
*((int *)((unsigned long long)(&foo) + 11979))
Where the constant 11979 is comefrom?
Is that constant is universal when applying convert static local variable to global in another platform?
Is there guarantee that part code is always success executed during runtime?
If not, is there a way UNIVERSALLY to convert static local variable to global aka accessing static local variable from outside its scope?
Writing code like that is a crime against nature. Exposing unprepared students to it is a crime against humanity.
Its author figured out that specific code with that specific compiler and that specific linker (including which versions of them), building with the specific options that that online compiler is using, the locl object was stored 11,979 bytes away from where the code for the foo function was stored. The code (int *)((unsigned long long)(&foo) + 11979) converts the address of &foo to an integer type, adds 11,979 to it, and converts it to a pointer to an int.
This code may break if other variables are added, if other functions are added, if various other modifications to the source code are made, if the target system of the build is changed, if the compiler is changed, and so on. There is essentially nothing that guarantees code like this will work except that if you change absolutely nothing about it, it may behave the same as it did before, like avoiding any vibration or air movement near a coin balanced on its edge might guarantee the coin does not fall over.
It does demonstrate that inside a process, the memory assigned to that process is generally visible and can be manipulated in devious ways, which is something programmers should know because malicious people can take advantage of it.
Where the constant 11979 is comefrom? Is that constant is universal
when applying convert static local variable to global in another
platform?
I have absolutely no idea what the magic number does :(
Is there guarantee that part code is always success executed during
runtime?
No, it shows a different result in godbolt with gcc 12.1
if not, is there a way UNIVERSALLY to convert static local variable to
global aka accessing static local variable from outside its scope?
Yes, there is, returning a pointer to the static variable:
#include <stdio.h>
int *foo(void)
{
static int x = 0;
return &x;
}
int main(void)
{
*foo() = 42;
printf("%d\n", *foo());
return 0;
}
Output:
42
I saw the link http://www.cs.uregina.ca/Links/class-info/cplusplus/Standards/Disk10/aliasing_c.html about aliasing in c. The program there is shown below.
/********************************
An example of aliasing in C.
Output:
3
3
********************************/
#include < stdio.h >
int main()
{
int G_Var = 2;
/* call SomeFunction with the Global Variable as a parameter */
SomeFunction(G_Var);
return 0;
}
/* InputVar becomes an alias fo G_Var */
void SomeFunction(int &InputVar)
{
int G_Var;
int InputVar;
/* Global Variable is set to new value */
G_Var = InputVar + 1;
/* Equivalent to G_Var = G_Var + 1 */
printf("%i\n", InputVar);
printf("%i\n", G_Var);
}
Is the code correct and is working according to what is commented in the code?
Whoever wrote the link was severely incompetent and shouldn't be teaching C. They should rather enlist in a beginner's class themselves.
int G_Var = 2; is not a global variable, it is a local one with automatic storage duration. Both the one in main() and the one inside the function.
The code posted is C++, not C. C does not have references.
The term alias/aliasing refers to when several pointers (or C++ references) may be assumed to point at the same memory location.
int InputVar; in the function conflicts with the parameter name so the code doesn't make any sense. In case there were no name conflict, the variable would be uninitialized and then used, which would be senseless.
Is the code correct and is working according to what is commented in the code?
Whoever wrote this example was so confused that it's really hard to be telling what they are trying to teach, or in which language for that matter. The code does not compile for multiple fundamental reasons. Just forget about this mess.
Four things to say:
C does not have C++-kind of aliases/references. It is a C++ feature only.
So,
/* InputVar becomes an alias fo G_Var */
void SomeFunction(int &InputVar)
is wrong.
G_Var is not a global variable. You declare it two times to be local to main and SomeFunction. If you want to declare G_Var as global variable it has to be declared once at global scope, not inside of a function, and only access it by its name, not declaring its type twice.
But beside that the use of global variables is deprecated. Rather use parameter passing.
SomeFunction() isn't declared before the call to it in main(). Usually this would give you a diagnostic as the compiler don't know what SomeFunction() is.
InputVar is used as reference parameter, but also declared twice in SomeFunction. Here is a conflict.
I guess you never compiled this code before asking, which is a fault. It would have answered many questions of yours including the main one.
"Is the illustration on Aliasing in C correct?"
"Is the code correct and is working according to what is commented in the code?"
No, it isn't. The whole code is defective.
It gives the impression that the authors didn't knew how to either write correct C nor C++ code.
Given a C code and a variable in the C code (global or a local variable of a function), is there a way to find the functions which uses this variable? This should also show the accesses to the variable by a function if it is also accessed through a pointer.
Tried to extract info using LLVM IR but seems difficult.
int a = 2;
int array1 = {1,2,3};
int function1(int c, int d) {
return c + d;
}
int function2 (int arg1[], int * p1, int *p2) {
int a;
return arg1[2]+ (*p1) +a + (*p2);
}
int main() {
int e =2, f=3,g;
g = function1(e,f);
int array2[] = {1,2,3,4};
g = function2(array1,&e,array2);
return 0;
}
variables and the functions which uses them
globals:
a - none,
array1 - function2, main
local variables :
function2:a - function2,
main:e - main, function2,
main:f - main,
main:g - main,
main:array2 - main,function2
is there a way to find the functions which uses this variable
Your best shot will be to use IDE, most of them will be able to trace references to global variables.
Alternatively, you can use static analysis tool like cxref (the one matching https://linux.die.net/man/1/cxref). I used it long time ago, and it was useful. There is a documentation tool with the same name - which might work.
As last resort, if you do not have any other choice, comment the variable declaration, and try building the code. The compiler will raise an error on every bad reference. (Minor exception: locally scoped variables that hides global definitions may not raise an error).
show the accesses to the variable by a function if it is also accessed
through a pointer.
This is extremely hard (impossible for real programs) with static analysis. Usually, this is done at runtime. Some debuggers (e.g. gdb watch) allow you to identify when a variable is being modified (including via pointers). With hardware support it is also possible to set 'read watch' in gdb. See gdb rwatch, and Can I set a breakpoint on 'memory access' in GDB?
The output of the following code is 0.
int account=2;
int main()
{
static int account;
printf("%d",account);
return 0;
}
Why it picked static variable over global variable? Because what I understand is that both global and static variables are stored in the heap and not in function stack , right? So what method it uses to use select one over another?
If multiple variables exist with the same name at multiple scopes, the one in the innermost scope is the one that is accessible. Variables at higher scope are hidden.
In this case you have account defined in main. This hides the variable named account declared at file scope. The fact that the inner variable inside main is declared static doesn't change that.
While the static declaration on a local variable means that it is typically stored in the same place as a global variable, that has no bearing on which is visible when the names are the same.
Consider this small self explaining program:
#include <stdio.h>
int bar = 123; // global variable, can be accessed from other source files
static int blark; // global variable, but can be accessed only in the same
// source file
void foo()
{
static int bar; // static variable : will retain it's value from
// one call of foo to the next
// most compilers will warn here:
// warning declaration of 'bar' hides global declaration
printf("foo() : bar = %d\n", bar); // won't use the global bar but the
// local static bar
bar++;
}
void quork()
{
int bar = 777; // local variable exists only during the execution of quork
// most compilers will warn here as well:
// warning declaration of 'bar' hides global declaration
printf("quork() : bar = %d\n", bar); // won't use the global bar but the
// local bar
bar++;
}
int main() {
foo();
foo();
printf("main() 1 : bar = %d\n", bar);
bar++;
quork();
quork();
foo();
printf("main() 2 : bar = %d\n", bar);
printf("blark = %d\n", blark);
}
Output:
foo() : bar = 0
foo() : bar = 1
main() 1 : bar = 123
quork() : bar = 777
quork() : bar = 777
foo() : bar = 2
main() 2 : bar = 124
blark = 0
Just to clarify for future readers, global and static variables are not stored in heap or stack memory.
https://www.geeksforgeeks.org/memory-layout-of-c-program/
They will either be stored in initialized data or uninitialized data.
Thats not the main question here, which was answered by dbush, but it is a misunderstanding in the original question.
Short answer: encapsulation.
static describes both lifetime and visibility of a variable, and its meaning changes depending on the context. My opinion is that it is one of the more useful and important language features for encapsulation in c. Ignoring the complex relationship to extern, here's a simplified description:
static variables defined at the file level have program lifetime and compilation unit visibility. This means all functions in a .c file can access/modify the variable, but other .c files won't know about the variable. This is super useful for making sure variables used across functions with a compilation unit don't accidentally link with variables in other compilation units. Personally, I highly recommend all file variables to be static by default. Only remove the static specifier if you really want another compilation unit to have access to it (although a getter function may be safer)
Variables declared static within a block scope (most importantly function scope) have program lifetime, and scope visibility. That means it functions as if you declared the variable globally in the file, but only code within that block scope can see it. It also means from one call to the next, the variable does not get destroyed and state can be transferred from call to call.
One really important difference with static variables is that they are default-initialized to zero. This differs from all other variables in c, and is the reason your program prints the value 0. Often times with trivial programs we don't notice the difference because the stack hasn't been polluted with variables yet, but it becomes critical for any program of size.
The most common use for this that I have seen is to enable one-time initialization within a scope. They are also extremely useful for synchronization primitives like pthread_mutex_t. One time I even implemented a state-machine with function-scope static variable.
an example:
int started;//oops, anybody in the entire program can change this value, especially with such a common name!
static int lastCall;
int callCount(void)
{
// This is default-initialized to 0
static int functionStaticVariable;
//Increment each time I'm called
++functionStaticVariable;
//tell the outside world that I'm the one who was called last
lastCall = 1;
//return (a copy of) my internal state.
return functionStaticVariable;
}
char *getSharedMemory(unsigned int bytes)
{
// Here I cannot see functionStaticVariable, but I can see globalVariable
//functionStaticVariable++; // this would cause a compilation failure
// static pointer is default-initialized to zero (i.e. NULL)
static char *sharedMemory;
if(sharedMemory == 0)
{
// This block only executes once, the first time the function is called.
// Actually this is a nice side-effect because it means if the function is never called we don't clutter the stack with unused memory
// Although we will probably never free this memory
sharedMemory = (char *)malloc(bytes);
}
// tell the outside world that this function has been called
lastCall = 2;//valid
//Woah, this is such a bad idea, but actually does _not_ return memory that gets invalidated
return sharedMemory;
}
Hopefully you can see with this pattern you could protect a variable by placing it inside a function and doing optional things like acquiring a mutex-lock in order to allocate the memory. You could even implement the double-lock pattern this way.
I secretly wish that all C++ programmers learned good c encapsulation, because actually the language really encourages it. You can do an incredible amount by placing only functions that need to communicate with each other together in a compilation unit. In a non-OOP language, this can be very powerful.
Full details of static and extern are described by https://en.cppreference.com/w/c/language/storage_duration.
The pragmatic reasoning behind why innermost variable decaration should be the one used: you're not always in control of what's outside your code. You want to be able to write a function that certainly works. If other programmers (say, in a larger team) could break your code just by the way they name variables in other parts of the code, programming would be more of a pain than it is now.
I'm still learning C to be used in microprocessors. In the beginning I used lots of globals. Now I'm trying to avoid it as much as a can, but for me it's not always clear to see how to do this.
For example a battery monitor, in this case there are 4 functions that need to read or modify a variable.
I have these functions all using the variable LowVoltage.
void Check_Voltage(){
checks current voltage against LowVoltage
}
void Menu_Voltage(){
a menu on the LCD screen to set the value of LowVoltage
}
void Save_LowVoltage(){
runs after the settings menu is finished to save LowVoltage to EEPROM
}
void Load_LowVoltage(){
reads EEPROM and sets LowVoltage at startup
}
Check_Voltage() and Save_LowVoltage() need to read LowVoltage.
Load_LowVoltage() need to write LowVoltage.
Menu_Voltage() needs to read and write LowVoltage.
How can I make this work without making LowVoltage global??
Would I need to make another function to read or write LowVoltage?
Something like this:
unsigned int Low_Voltage(short Get, unsigned int Value){
static unsigned int LowVoltage;
if(Get) return LowVoltage;
else LowVoltage= Value;
}
Or are there better ways to do this? I guess there must be :)
I've been reading about structures lately, but to be honest I don't fully understand them and I'm not even sure it would help me in cases like this?
There are several choices to sharing a variable among functions:
Allocate your variable in static memory - this is pretty much what your code does. Your two choices there are function-static, translation unit-static, and global
Pass a pointer to variable as function parameter - This choice requires passing the pointer around in some form
Use thread-local storage with clever initialization - This choice is not usually available when you work with microcontrollers; I list it here for completeness.
In your case, I think that using a translation unit-static variable would be appropriate. Put implementations of the four functions into a single C file, and declare LowVoltage at the top as a static variable:
static unsigned int LowVoltage;
This simple but efficient encapsulation mechanism gives you all benefits of having a global variable, without the drawbacks of having a global variable:
All functions inside the C module "see" this variable, and can freely manipulate it
No other functions outside the C module can access this variable. They can declare their own LowVoltage variable, giving it an entirely different meaning.
Two solutions I can think of
Make the function signatures like this
unsigned int Load_LowVoltage(unsigned int lowVoltage);
and then pass LowVoltage and assign to it the return value, like this
LowVoltage = Load_LowVoltage(LowVoltage);
Modify LowVoltage inside the function and pass a pointer to your original LowVoltage like this
void LowVoltage(unsigned int *lowVoltage)
{
*lowVoltage = modifiedValue;
}
then you can use it like this
Load_LowVoltage(&LowVoltage);
I think the second solution is cleaner and since you are in un environment where resources are limited, it's also better in that sense. But they both are easy to implement and work as good.
You could create a struct holding all battery parameters, for example:
typedef struct {
int low_voltage;
int voltage;
int capacity;
int temperature;
...
} BatteryData
At the start of your program you allocate memory for it and initialise members to some starting values:
BatteryData *battery = malloc(sizeof(BatteryData));
battery->low_voltage = 0;
...
Then you pass pointer to the whole struct to functions that set or read individual values, for example:
void Load_LowVoltage(BatteryData *battery){
//reads EEPROM and sets LowVoltage at startup
int eeprom_val = get_low_voltage_from_eeprom();
battery->low_voltage = eeprom_val;
}
Free the structure when not needed:
free(battery);