anon
anon

Reputation:

Difference between global variables and variables declared in main in ARM C

I've been trying to use C in Keil to write some test code for my TM4C123G, which uses an ARM microcontroller. I have no clue about ARM assembly, but I have written some assembly code for an AVR microcontroller in the past.

Where are the values of the variables stored, if we declare a variable in C as global, as opposed to declaring it in main?

Are there general guidelines as to whether we should declare a variable global as opposed to in main (when it comes to writing C for a microcontroller) ?

Upvotes: 5

Views: 5604

Answers (3)

old_timer
old_timer

Reputation: 71566

Globals are fine they have a place especially in embedded things like microcontrollers where you are extremely tight on resources. Globals make it easy to manage your resources where locals are very dynamic and difficult at best to not get into trouble.

But... As far as assembly goes, there are no rules, there is not really a notion of local versus global that is strictly a higher level language thing. Now there may be implementations of assembly languages that allow/force such things, understand that C is a standard (as others) that cross platforms and are not specific to one. But assembly not only does not have a standard, but is also processor specific. the assembly language is defined by the assembler (the program that parses it and turns it into machine code). And anyone and their brother can bang out an assembler and make up whatever language or rules they want.

In general if you are trying to hand implement C code in assembly instead of having the compiler do it (or instead of just having the compiler do it and at least see what it does). Your globals unless optimized out are going to get a home in ram. Locals may or may not depending on optimization get a place on the stack, they may just live temporarily in registers, depends on the processor number of registers available the trade off between preserving registers that contained something else to preserving the local in favor of keeping the something else in a register.

You should just take some simple functions (not necessarily complete programs) and see what the compiler does.

if you want to write in pure assembly and not have the notion of converting C you would still have the same dilemma of do I keep something in a register for a long time, do I put it on the stack for the duration of this chunk of code or do I assign it an address where it lives forever.

I suggest you be open minded and try to understand the whys and why nots, a lot of these kinds of rules, no globals, small functions, etc are preached not because of facts but just because of faith, someone I trust told me so I preach it as well, not always but sometimes you can dig in and find that the fear is real or the fear is not real, or maybe it applied 30 years ago but not anymore, and so on. An alternative to a global for example is a local at a main() or top level that you keep passing down as you nest in, which basically means it is a global from a resource perspective. In fact depending on the compiler (an extremely popular one in particular) that one main level local that is passed down, actually consumes resources at each nesting level consuming a significantly higher quantity of ram than if it had just been declared a global. The other side if it is not inefficient memory consumption but access, who can mess with that variable and who cant, locals make that quite easy, a fair amount of laziness, you can be messy. Have to take care with globals to not mess them up. Note static locals are also globals from a resource perspective they sit in the same .data space for the duration of the program.

There is a reason, many reasons why C cannot die. Nothing has come along that can replace it. There is a reason why it is basically the first compiler for each new processor/instruction set.

Write some simple functions, compile them, disassemble, see what is produced. take some of your embedded/bare metal applications for these platforms, disassemble, see what the compiler has done. Globals and static locals that cant be optimized out get an address in .data. Sometimes some or all of the incoming parameters get stack locations and sometimes some or all of the local variables consume stack as well, has to do with the compiler and optimization if you chose to optimize. Also depends on the architecture a CISC that can do memory and register or memory to memory operations doesnt have to move stuff in and out of registers all the time RISC often does have to exclusively use registers or often use registers, but also often has a lot more available. So the compiler knows that and manages the home for the variables as a result.

Everyone is going to put globals and static locals in ram (unless they can optimize out). traditional x86 brings the parameters in on the stack anyway and is going to put the locals there too and just access them there. a mips or arm is going to try to minimize the amount of ram used, and lean on registers, trying to keep some of the variables in registers exclusively and not consume stack.

An assembly programmer, pre-compilers, used a lot of the equivalent of globals, pick an address for each variable. now post compilers, you can choose to just do it that way setup all of your variables and hardly use the stack other than returning from calls, or you can program as if you were a compiler and make some rules or simply follow the compilers convention and have some disposable registers and others preserved and lean on the stack for preservation and local to the function items.

At the end of the day though assembly does not have a notion of global vs local any more than it has a notion of signed vs unsigned vs pointer vs array or anything like that that a high level language would have.

Upvotes: 0

Timmy Brolin
Timmy Brolin

Reputation: 1181

  1. The compiler will put global variables in the "data" or "bss" memory segment. This allocation is permanent, so the variable will never lose its value. Function-local variables are allocated dynamically on the stack, and disapears when the function returns.
  2. Use global variables when the variable must keep its value between function calls, and must be accessible by code in multiple functions and/or files. Use function-local variables for everything else.

There are also "static" variables. They function the same way as global variables, but have a more limited namespace. They are used as file-local variables and function-local variables which keep their value between function calls.

Upvotes: 1

Michael Dorgan
Michael Dorgan

Reputation: 12515

Globals in ARM cause an offset to be placed in the calling function's "pool" area. In general, each global needs its own offset. If you do decided to use globals, place them into a single structure so that all the variables can be accessed via a singel pool offset.

Variables defined at the function level live on the stack. These, within reason, can be accessed with a simpler offset from the stack register and tend to be a touch more efficient opcode wise, and perhaps cache wise, depending on what kind of system you are using.

When to use either? Outside of the global vs. local holy wars of maintainability, it comes down to what else your code wants to do. If some variable is being used in a ton of places and you don't want to pass it around as a parameter (a sign that perhaps your design needs work...) then a global would be the way to go. If you need to access this variable across multiple assembler packages (that desing thing again...) then perhaps a global is also fine.

Most of the time though, I would go with local variables. They are much more thread safe, and from a above, tend to be more efficient. They are easier to maintain as well, because there scope is much more confined - which also helps compilers do there jobs better as well.

Upvotes: 3

Related Questions