String variable Vs string literal
A string literal is a sequence of characters that are directly written in the code, while a string variable is a named memory location that stores a reference to a string value that can be changed during runtime.
String Variable
Here, the first printf is to print the address of the msg1 variable. So, that’s a reason I use &msg1.
The second one is to print the value which is contained in the variable msg1. That’s why I use msg1 here.
You can see the output in the SWV ITM Data Console, the address of the msg1 variable is 0x2001ffdc. This actually belongs to the RAM address. So because RAM starts from 0x200 in this microcontroller.
And look at the value of the msg1 variable, it is also 0x2001ffdc. When you have an array, the address of msg1 or the value of msg1, both are the same.
Here we have an array, let’s say 0x2001ffdc, 0x2001ffde, 0x2001ffdf, like that. “Hello” is the first element and this is msg1.
So, if you print the value of this definitely it is going to print 0x2001ffdc.
What if you do &msg1?
&msg1 is nothing but &(msg1+0). Here, msg1+0 is the first element. So, that’s basically what you’re asking is the address of the first element. The address of the first element is 0x2001ffdc. That’s why, in an array, the value of the msg1 array variable or the address of the msg1 array variable is the same. So, you can see that those are the same values.
Now you can also go to the variable window, you can see that if you expand this “Hello how are you?” These characters are stored from this address onwards, as shown in Figure 3.
Basically, msg1 is a local variable or a local array. It is not global data, it’s local to the main function.
From our earlier discussion on variables you know that local variables are transient variables. That’s why it doesn’t make any sense to store “Hello how are you?” in the data memory permanently throughout the lifespan of a program. So, the global data will be stored in the data memory throughout the lifespan of a program.
“Hello, how are you?” data is actually transient data. That’s a reason it doesn’t make any sense to store this permanently on the data memory. That’s why this data is copied from the flash memory into this array during the runtime of the program.
Now let’s investigate that. Let’s open the disassembly window and see.
Let’s just step over and take a look at the value of the r3 register. So, that is a flash address, 0x8001354. But we know msg1 belongs to RAM. Arrays are created in the RAM.
Now let’s open the memory browser and type 2001ffdc. Look at Figure 5, these are the memory allocations and this is where our array is created. So, these memory locations belong to our array, that is msg1.
Now what happens is, these instructions will copy “Hello how are you?” this string from flash into msg1 array. So, because when you create the binary, that string is a part of the binary, which will be stored in the flash memory.
So, you have to note one point here, this data copying is not done by the startup code, this is done during the function execution.
But here msg1 is not global data, this is transient data or local data. That’s why data copying happens when that function is called. Here the main is called. So, that’s why it is taking place here during the runtime of the function. And once the main function exits this data(msg1) will be removed from the RAM. So, strictly speaking, this variable is actually created in the stack memory of the RAM.
If you are confused, let me explain with some diagrams.
Look at Figure 6, here we have RAM. In the microcontroller, we have RAM of 192 kilobytes(192KB).
There will be a start and end of RAM. 0x2000-0000 is the start of the RAM and 0x2002-FFFC is the end of the RAM.
And the RAM will be divided into a couple of sections like
→ One section is for global data.
→ Another section for stack data. Here, the transient variables will be created and destroyed.
→ Some part of the RAM will be reserved for the heap for dynamic memory allocation. Here we don’t care about the heap because we are not using any dynamic memory allocation APIs.
When the function is called all local variables are created in the stack, and when the program exits those memories will be reclaimed.
So, a stack will be tracked by the stack pointer(SP) register of the processor. Here there will be the start of the stack(S-stack) and the end of the stack(E-stack).
Whenever the variables are created in the stack, the stack pointer actually decrements. And whenever variables are destroyed a stack pointer will reclaim those memory addresses. So, dynamically the stack will shrink and expand. In our case, the msg1 variable or array is a local variable. So, that’s a reason msg1 will be created in the stack.
And we know that there is also a flash memory, which is our permanent memory flash. When you load the binary into the flash, the “Hello how are you?” that string is stored in the flash memory.
Data copy takes place during the run-time of a function.
When the main function is called that string is copied into the msg1[] array. This is not done by the startup code. This is done during the runtime of the function.
Suppose, in the global section, there is an array called global msg1[] array, in that case, the startup code would have copied the string into a global data into the global section. That happens because control comes prior to the main. In that case, the startup code would have copied that data from flash to the global array. So, in our program there is no global array, this is what happens behind the scenes.
Now let me just step over and execute these instructions, and here you can see that the string is copied from flash into RAM into this array, as shown in Figure 7.
Remember that, now you have two copies of this string. Copy-1 is created in the Flash and one more copy is created in the stack or the RAM, that is copy-2. So, 2 copies are created.
When you do msg1[0] = ‘K’; (if you assign some other value) Here you change copy-2, not copy-1. Copy-1 cannot be modified, because that is in the flash.
So, you cannot just change the contents of the flash using your pointer access. That’s not possible.
String literal or string constant
Here we are add one more string definition → char *pmsg2 = “fastbitlab.com”;
After that, I’ll print msg1 and msg2. So, you can use %s, as I said before %s needs char *, which is terminated with a null character.
Then, I’ll print the address of the pmsg2 variable, because pmsg2 is a pointer variable. So, &pmsg2.
Then, I’ll print the value of the pmsg2 variable, I will write pmsg2.
Let’s analyze what could be the result of the address of the ‘pmsg2’ variable and the value of the ‘pmsg2’ variable.
Here(line 20), &pmsg2 is the address of *pmsg2 variable. We know that *pmsg2 is a local variable. So, the address of this variable will be in RAM. Definitely, it is going to print some RAM addresses. So, both are local variables.
What about this string ”fastbitlab.com”? Now, this is a string literal or a string constant that is stored in a flash. “Hello how are you?” and “fastbitlab.com” both are stored in a flash. Why? Because it is part of the binary. When you create a binary it is part of the flash. So, both are living in ROM or flash.
char msg1[] = “Hello how are you?” In this case there is a data copy.
But, char *pmsg2 = “fastbitlab.com” in this case there is no data copy, just a pointer assignment. So, the pmsg2 is going to display a flash address.
Let’s check the output. 0x2001ffd8 is a RAM address. So, 0x800130c is a flash address. So, the pmsg2 variable living in RAM points to flash(line 16). So, pmsg2 is created in the stack.
Here pmsg2 is created in stack and string is created in stack flash. But pmsg2 is created in the stack and pointing to flash. So, that’s a reason you can’t do pmsg2[0] = ‘k’; (you can’t assign some other value). Because pmsg2 is pointing to flash.
You cannot change the flash contents like this. It’s not allowed. Even if you do this it does not affect the microcontroller. Because, we write access to the flash will be detained or it will be blocked by the flash controller unless you give some special instructions to the flash controller like you have to insert some password and all, and you have to unlock write access to the flash, then only you can do this technique to write into the flash. Otherwise, simply you cannot modify the flash content by taking its address. The flash controller will not allow you to do that. So, this does not affect the microcontroller.
But the same code, if you try it on your host computer, then may lead to an unexpected result, and your application may even crash.
Here we add msg1[0] = ‘b’; //Replace ‘h’ by ‘b’.
And I do the same thing for the pointer also.
pmsg2[0] = ‘b’;
Let’s check this code. Here, the compiler didn’t issue any errors. The compiler has no problem with this code, even though this code is wrong. The compiler actually ignored this, so the compiler basically won’t throw any warning or error on this (line 19).
So, pmsg2[0]= ‘b’ is the wrong code. So, you should not be doing something like this. Because you are trying to modify read-only memory.
That’s why, why should you maintain the *pmsg2 variable definition as a constant data definition. The best way to write this string definition is char const(as shown in Figure 11, line 16).
This is a valid or more suitable string definition for a string literal or a string constant.
Now, if you try to execute this there is an error. Here we can see that there is an error. So, the compiler will not allow you to do something like this.
For a time being let’s remove the const and let’s try once again.
You can see that ‘h’ is replaced by ‘b’, but “fastbitlab.com” this string is not modified. So, it has no effect.
That’s about the difference between a string variable and a string constant or a string literal. So, don’t forget to use const here, that’s a good practice.
Now let’s execute the same program on our host and let’s see how the host responds to this program. So, let’s run.
Here we can see that “H” is replaced by “b”. pmsg2[0] =’b’ this line is disabled, That’s ok.
And then 0061FF08 is the RAM address. There is a difference between 0061FF08 and 00405044. So, 00405044 belongs to the read-only section or read-only memory. So, this is happening on the computer.
Enable pmsg2[0] = ‘b’; and let’s see what happens. Here we are trying to change the content of the read-only memory location. Let’s see how this program behaves on the host.
Let’s run the program. And here you can see that the application crashes, as shown in Figure 14.
Because the operating system detected that you are trying to change the content of the read-only section and that’s the reason the operating system terminated your executable.
We saw that on the microcontroller it has no effect. That’s a reason if you have some string definition, then always you should maintain the data as constant. So, if anyone tries to modify that you can see that the compiler throws an error.
FastBit Embedded Brain Academy Courses
Click here: https://fastbitlab.com/course1