简体   繁体   中英

Are there valid reasons to declare variables static inside the main() function of a C program?

I am aware of the various meaning of the static keyword in C, but my question is more specific: Is there any valid reason to declare some variables in the main() function of an embedded C-language program as static?

Since we are talking about variables declared inside the braces of main(), the scope is already local to main(). As regards persistence , the main function is at the top of the call stack and can't exit as long as the program is running. Hence, on the face of it, there would seem to be no valid reason to declare using static inside of main().

However, I notice that an effect of using static declarations is to keep variables and arrays from being placed on the stack. In cases of a limited stack size, this could be important.

Another possible, but rather uncommon case is that of main() calling itself recursively, where you might need some variables to persist at different levels of the recursion.

Are there any other possible valid reasons to use static declarations of variables inside the body of a main() function?

.. valid reasons to use static declarations of variables inside the body of a main() function?

  1. Initialization

     int main(void) { static int a; // initialized to 0 int b; // uninitialized 
  2. In C, main() call be called. ref So the usual issues about static variables apply.

     int main(void) { static int c; // Only one instance int d; // One instance per call ... main(); 
  3. Memory location. Various compilers will organize main() 's variable. It is not specified by C, so a compiler dependent issue.

A variable has three attributes besides type:

  • Scope (visibility)
  • Life-time
  • Location

Selection of these attributes is best done according to the semantics of the code. While while a static variable in main() may appear to have the same scope and lifetime as a non-static so differ only in location, it does not have the same semantics . If - as is likely under development - you decide to move or reorganise the code in main() into a sub-routine, the use of static will cause such code to behave differently and potentially incorrectly.

My advice therefore is that you use the same determination of the use of static in main() as you would any other function and not treat it as a special case semantically identical to a non-static. Such an approach does not lead to reusable or maintainable code.

You have to partition the memory into stack, heap and static space in any case, if you have a stack variable with a lifetime of the entire process you rob Peter to pay Paul by using more stack in exchange for less static space, so it is not really an argument, except for the fact that insufficient memory is then a build-time issue rather then run-time, but if that is a serious concern, you might consider making all or most variables static as a matter of course (necessarily precluding reentrancy, and thus recursion and multi-threading). If stack space were truly an issue, recursion would be a bad idea in any case - it is a bad idea in most cases already, and certainly recursion of main() .

I see a practical reason to declare a static variable inside main (with most compilers on most desktop or laptop operating systems): a local variable inside main is consuming space on the call stack . A static variable consumes space outside the call stack (generally in the .bss or .data segment, at least in ELF executables)

That would make a big difference if that variable takes a lot of space (think of an array of million integers).

The stack space is often limited (to one or a few megabytes) on current (desktop, laptop, tablet) systems.

On some embedded processors, the stack is limited to less than a kilobyte.

I think you have said it. It one makes them static which for main() is not very interesting, second it makes them what I call local globals, it essentially puts them in .data with the globals (and not on the stack), but restricts their scope of access like a local. So for main() I guess the reason is to save some stack. If you read around stack overflow though it seems like some compilers put a big stack frame on main() anyway, which most of the time doesnt make sense, so are you really saving any space? Likewise if they are on the stack from main unless you recursively call main they are not taking any more or less space being in .data vs the stack. if they are optimized into registers, then you still burn the .data where you wouldnt have burned the stack space, so it could cost you a little space.

The result of trying to indirectly access an object defined with automatic storage duration, ie a local variable, in a different thread from which the object is associated with, is implementation defined (see: 6.2.4 Storage duration of objects, p5).

If you want your code to be portable you should only share with threads objects defined with static, thread, or allocated storage duration.

In this example, the automatic object defined in the main should have been defined with static:

int main( void )
{
    CreateThreads();
    type object = { 0 };   //missing static storage-class specifier
    ShareWithThreads( &object );
}

As already mentioned, the main reason would be to save stack space and also give you a better idea of the actual stack size need of your program.

Another reason to declare such variables static would be program safety. There are various embedded system design rules that need to be considered here:

The stack should always be memory-mapped so that it grows towards invalid memory and not towards .bss or .data . That means that in case of stack overflow, there is a chance for the program to raise an exception, rather than going Toyota all over your static variables.

For similar reasons, you should avoid declaring large chunks of data on the stack, as that makes the code more prone to stack overflows. This applies particularly to small, memory-constrained microcontroller systems.


Another possible, but rather uncommon case is that of main() calling itself recursively

That's nonsense, no sane person would ever write such code. Using recursion in an embedded system is very questionable practice and usually banned by coding standards. Truth is, there are very few cases where recursion makes sense to use in any program, embedded or not.

Once reason is that the offset of a static variable in the executable file is determined at link time and can be relied upon to be at the same place.

Therefore, a useful purpose of a static variable at the main level is to include program version data as readable strings or binary readable data that later can be used to analyze/organize executables without needing to have the original source code or any program-specific utilities, other than a hex dump program. We used this hack back in the day when deploying programs where the target system could not be relied upon to have any development tools.

For example,

int main(void)
{
    // tag to search for revision number
    static char versionID[3] = {'V','E','R'};
    // statically embedded program version is 2.1
    static unsigned char major_revision = 2;
    static unsigned char minor_revision = 1;

    printf("\nHello World");
    return 0;
}

Now the version of the program can be determined without running it:

$ od -c -x hello-world | grep "VER"

0010040 001 002 VERGCC : ( U bunt

Actually, there's an enormous reason!

If you declare a variable as static within main() (or, any function ...), you are declaring that this local variable is also static .

What this means is that, if this function calls itself ... (which main() probably wouldn't do, although it certainly could ...) ... each recursive instance would see the same value, because this variable isn't being allocated on the stack. (Because, ummm, "it is static !")

"Stack size" is not a valid reason to use static. (In fact, it has nothing to do with it.) If you're concerned about having room "on the stack" to store something, the correct thing to do is to "store it in the heap, instead," using a pointer variable. (Which, like any variable, could be static, or not.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM