简体   繁体   中英

Declaring structures within functions in C

I have a structure that only one function must access. The function converts tokens like "k, K, kb, KB, m, M, mb, MB, ..." into an actual unit. The purpose of this is to simplify a configuration file.

So, suppose we have:

static uint32_t real_unit(const char *str)
{
    struct u2type {
      char key[3];
      uint32_t val;
    } const u2types[] = {
       { "k", KB_UNIT },
       { "K", KB_UNIT },
       { "kb", KB_UNIT },
       { "KB", KB_UNIT },
       { "m", MB_UNIT },
       { "M", MB_UNIT },
       { "mb", MB_UNIT },
       { "MB", MB_UNIT },
       { "g", GB_UNIT },
       { "G", GB_UNIT },
       { "gb", GB_UNIT },
       { "GB", GB_UNIT },
       { { 0 }, 0 }
    };

    ... code to look up str ...
}

I have seen other programs where struct u2type would be declared as static (again, within a function) and I can't see how that is useful. The structure is not going to change, it will always be the same every time the function is entered. That's why I made it const.

Yet, I have seen many people do statc struct foo { ... } const foos[] = { ... }, within a function where the scope is just obvious.

Is there any benefit to doing that? I try to study ASM output prior to coming to SO with optimization questions like these, but I am not an assembly guru :)

EDIT:

Yes, I know this approach smells like feet. Some projects just have odd requirements (typically mandated by odd people). The question, however remains entirely separate from the use of the function.

Making it const and making it static do two different things.

  • if it is const, each function call gets its own unchangeable instance of the struct
  • if it is static there is one changeable instance of the struct shared across all function calls

It sounds as though what you want is a struct instance that is both static and const, which is a reasonable thing to do.

Performance wise, the static version should have a slight edge, as construction of the struct instance will only be done once.

If you declare your array static, it will be placed in the data section of the executable and initialized only once (on first access) or even not (it might be initialized in the executable already).

Without static, the data will be on the stack of each of the function's invocations, and initialized every time the function is called.

Just a little nitpick, when you say you've seen code where struct u2type is static, this is not really true. Although the static storage specifier appears before the struct, it really applies to the variable, in this case, the array. Even with

static struct foo { ... } foos [] = { ... };

You can then do

struct foo foo1={ ... };

and foo1 will be an automatic variable.

If you declare a variable static within a function it is only initialized once when the function is entered for the first time. If you declare it non-static it is initialized each time the function is entered.

In your case it can make a slight difference. With static the array will be allocated in the static storage and initialized no more than once. Without static it will be allocated on stack and each time the function is called.

Local variables or constants are allocated on the stack. Their existence lasts only during the function execution and their value is lost as soon as the function returns. Allocation and assignment take place each time the function is called.

Declaring a local variable or constant static means that its value will be kept from one call to the next. This is achieved by allocating it globally instead of on the stack. Allocation and assignment are performed only once, which in case of big data structures in frequently called functions may lead to performance improvments.

Eeeww. At least change your functions name to 'case_insensitive_guess_unit'. Most of those aren't 'real' units, and those which are ('K' for example is Kelvin not kilo, 'b' is usually bit and 'B' byte) aren't the units you're returning.

If the spec is k[b] -> 1000, m[b] -> 1000000 etc, then a simple if/else is probably faster and cleaner.

...

// so, do you want odor-free, or fast ?
switch (str[0]){
case 'g': case 'G':
  return GB_UNIT;
case 'k': case 'K':
  return KB_UNIT;
case 'm': case 'M':
  return MB_UNIT;
}

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