Объявление структур внутри функций в C - PullRequest
4 голосов
/ 25 марта 2009

У меня есть структура, к которой должна иметь доступ только одна функция. Функция преобразует токены, такие как "k, K, kb, KB, m, M, mb, MB, ...", в фактическую единицу. Целью этого является упрощение файла конфигурации.

Итак, предположим, что у нас есть:

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 ...
}

Я видел другие программы, в которых struct u2type была бы объявлена ​​как статическая (опять же, внутри функции), и я не вижу, насколько это полезно. Структура не изменится, она всегда будет одинаковой при каждом входе в функцию. Вот почему я сделал это const.

Тем не менее, я видел, как многие люди делали statc struct foo {...} const foos [] = {...} внутри функции, где область видимости просто очевидна.

Есть ли польза от этого? Я пытаюсь изучить выходные данные ASM, прежде чем перейти к SO с такими вопросами по оптимизации, но я не гуру сборки:)

EDIT:

Да, я знаю, что этот подход пахнет как ноги. У некоторых проектов просто странные требования (обычно обязательные для нечетных людей). Вопрос, однако, остается совершенно отдельным от использования функции.

Ответы [ 6 ]

13 голосов
/ 25 марта 2009

Делая это постоянным и делая статичным, делайте две разные вещи.

  • если это const, каждый вызов функции получает свой собственный неизменяемый экземпляр структуры
  • если он статический, существует один изменяемый экземпляр структуры, общий для всех вызовов функций

Звучит так, как будто вам нужен экземпляр структуры, который является и статическим, и константным, что разумно сделать.

С точки зрения производительности, статическая версия должна иметь небольшое преимущество, поскольку создание экземпляра структуры будет выполнено только один раз.

5 голосов
/ 25 марта 2009

Если вы объявите ваш массив статическим, он будет помещен в раздел данных исполняемого файла и инициализирован только один раз (при первом обращении) или даже нет (он может быть уже инициализирован в исполняемом файле).

Без статических данных данные будут в стеке каждого из вызовов функции и инициализируются при каждом вызове функции.

Просто немного придирчиво, когда вы говорите, что видели код, где struct u2type является статическим, это не совсем так. Хотя спецификатор статического хранилища появляется перед структурой, он действительно применяется к переменной, в данном случае к массиву. Даже с

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

Вы можете сделать

struct foo foo1={ ... };

и foo1 будут автоматическими переменными.

0 голосов
/ 25 марта 2009

...

// 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;
}
0 голосов
/ 25 марта 2009

Eeeww. Как минимум измените название вашей функции на case_insensitive_guess_unit. Большинство из них не являются «настоящими» единицами, и те, которые (например, «K» - это Кельвин, а не килограмм, «b» - это, как правило, бит, а байт «B») - это не единицы, которые вы возвращаете.

Если спецификация k [b] -> 1000, m [b] -> 1000000 и т. Д., То простой if / else, вероятно, быстрее и чище.

0 голосов
/ 25 марта 2009

Локальные переменные или константы размещаются в стеке. Их существование длится только во время выполнения функции, и их значение теряется, как только функция возвращается. Распределение и присвоение происходит каждый раз, когда вызывается функция.

Объявление локальной переменной или статической константы означает, что ее значение будет сохраняться от одного вызова к другому. Это достигается за счет глобального распределения, а не в стеке. Распределение и назначение выполняется только один раз, что в случае больших структур данных в часто вызываемых функциях может привести к снижению производительности.

0 голосов
/ 25 марта 2009

Если вы объявляете переменную static внутри функции, она инициализируется только один раз, когда функция вводится впервые. Если вы объявляете его нестатичным, он инициализируется каждый раз при входе в функцию.

В вашем случае это может иметь небольшое значение. При static массив будет размещен в статическом хранилище и инициализирован не более одного раза. Без static оно будет размещено в стеке и каждый раз, когда вызывается функция.

...