5

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) ?

codingEnthusiast
  • 3,800
  • 2
  • 25
  • 37
  • 2
    global variable is never good idea. make it static/file-scope. or avoid it completely. – user3528438 Apr 17 '15 at 20:31
  • 2
    There are many cases where it is safe and OK to use global variables. They are certainly bad in large code bases, but in the case of a microcontroller globals are not so uncommon. – dtech Apr 17 '15 at 20:37
  • 2
    It's actually being suggested by some tutorials I've found on the web, maybe to make these variables visible to every function and avoid passing them as arguments, thus ending up with void functions of void arguments (that's what it comes to in the end, but i'm not sure if that's the reason). – codingEnthusiast Apr 17 '15 at 20:42
  • using a global to avoid passing a parameter isn't a great justification. use them when they have logical meaning. they are values which change the way your program runs across more than one translation unit. globals add state to your program and when you change them often it can make debugging more difficult. – Steve Cox Apr 17 '15 at 21:08
  • 1
    @ddriver equivalent to "why don't government ban tobacco?" – user3528438 Apr 17 '15 at 21:11
  • 2
    @user3528438 - so the standard committee is allowing harmful language features for profit? Doesn't make sense... – dtech Apr 17 '15 at 21:11
  • 1
    @ddriver people even write books like to tell people what language features to avoid in order to write clean code. C is cleaner than c++ in terms of features, but far from "every feature exist for a good reason". Ugly features, historical features, hacks, people need them to make things work, so there they are. – user3528438 Apr 17 '15 at 21:22
  • 1
    @ddriver yes, get used to it. there are many standardized languages with plenty of harmful and dangerous features, e. g. JavaScript's implicit conversions, non transitive equality comparisons, the with clause; in C and C++, there's implicit array-to-pointer comparison, the whole preprocessor thingy, and, yeah, global variables. – The Paramagnetic Croissant Apr 17 '15 at 22:26
  • 7
    There is nothing wrong with global variables if you use them correctly. Just like pointers, just like manual memory management. – dtech Apr 17 '15 at 22:28

3 Answers3

3

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.

Michael Dorgan
  • 12,453
  • 3
  • 31
  • 61
1
  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.

Timmy Brolin
  • 1,101
  • 1
  • 8
  • 18
0

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.

codingEnthusiast
  • 3,800
  • 2
  • 25
  • 37
old_timer
  • 69,149
  • 8
  • 89
  • 168
  • I imagine they no longer teach the rule that a function should never be so long as to not fit on a printed page (using a 12 pt font for those that played the font game to get around the rule). Raise your hand if you even have a printer... – old_timer Apr 18 '15 at 00:04