Выбор статического над глобальным. Зачем? - PullRequest
0 голосов
/ 12 сентября 2018

Вывод следующего кода равен 0.

int account=2;

int main()
{
    static int account;
    printf("%d",account);
    return 0;
}

Почему он выбрал статическую переменную вместо глобальной переменной?Потому что я понимаю, что глобальные и статические переменные хранятся в куче, а не в стеке функций, верно?Так какой метод он использует, чтобы выбрать один над другим?

Ответы [ 5 ]

0 голосов
/ 06 ноября 2018

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

0 голосов
/ 04 ноября 2018

Краткий ответ: инкапсуляция.

static описывает время жизни и видимость переменной, и ее значение изменяется в зависимости от контекста.Я считаю, что это одна из наиболее полезных и важных функций языка для инкапсуляции в c.Игнорируя сложное отношение к extern, вот упрощенное описание:

static переменные, определенные на уровне файлов, имеют время жизни программы и единица компиляции видимость.Это означает, что все функции в файле .c могут обращаться к переменной или изменять ее, но другие файлы .c не будут знать о переменной.Это super полезно для обеспечения того, чтобы переменные, используемые в функциях с модулем компиляции, случайно не связывались с переменными в других модулях компиляции.Лично я настоятельно рекомендую, чтобы все файловые переменные были статическими по умолчанию.Удаляйте спецификатор static только в том случае, если вы действительно хотите, чтобы другой модуль компиляции имел к нему доступ (хотя функция получения может быть более безопасной)

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

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

Наиболее распространенное использование для этого, которое я видел, состоит в том, чтобы включить однократную инициализацию в пределах области.Они также чрезвычайно полезны для примитивов синхронизации, таких как pthread_mutex_t.Однажды я даже реализовал конечный автомат со статической переменной области действия.

пример:

int started;//oops, anybody in the entire program can change this value, especially with such a common name!
static int lastCall;

int callCount(void)
{
    // This is default-initialized to 0
    static int functionStaticVariable;

    //Increment each time I'm called
    ++functionStaticVariable;

    //tell the outside world that I'm the one who was called last
    lastCall = 1;

    //return (a copy of) my internal state.
    return functionStaticVariable;
}

char *getSharedMemory(unsigned int bytes)
{
    // Here I cannot see functionStaticVariable, but I can see globalVariable
    //functionStaticVariable++; // this would cause a compilation failure

    // static pointer is default-initialized to zero (i.e. NULL)
    static char *sharedMemory;
    if(sharedMemory == 0)
    {
        // This block only executes once, the first time the function is called.
        // Actually this is a nice side-effect because it means if the function is never called we don't clutter the stack with unused memory
        // Although we will probably never free this memory
        sharedMemory = (char *)malloc(bytes);
    }

    // tell the outside world that this function has been called
    lastCall = 2;//valid

    //Woah, this is such a bad idea, but actually does _not_ return memory that gets invalidated
    return sharedMemory;
}

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

Я тайно желаю, чтобы все программисты на C ++ узнали хорошую инкапсуляцию c, потому что на самом деле язык действительно поощряет это.Вы можете сделать невероятное количество, поместив только функции, которые должны общаться друг с другом, в модуле компиляции.На языке, отличном от ООП, это может быть очень мощным.

Полная информация о static и extern описана в https://en.cppreference.com/w/c/language/storage_duration.

0 голосов
/ 12 сентября 2018

Рассмотрим эту небольшую самообъясняющую программу:

#include <stdio.h>

int bar = 123;     // global variable, can be accessed from other source files

static int blark;  // global variable, but can be accessed only in the same
                   // source file

void foo()
{
  static int bar;  // static variable : will retain it's value from
                   // one call of foo to the next
                   // most compilers will warn here:
                   // warning  declaration of 'bar' hides global declaration

  printf("foo() : bar = %d\n", bar);  // won't use the global bar but the
                                      // local static bar
  bar++;
}

void quork()
{
  int bar = 777;   // local variable exists only during the execution of quork
                   // most compilers will warn here as well:
                   // warning  declaration of 'bar' hides global declaration

  printf("quork() : bar = %d\n", bar);  // won't use the global bar but the
                                        // local bar
  bar++;
}

int main() {
  foo();
  foo();
  printf("main() 1 : bar = %d\n", bar);
  bar++;
  quork();
  quork();
  foo();
  printf("main() 2 : bar = %d\n", bar);
  printf("blark = %d\n", blark);
}

Выход:

foo() : bar = 0
foo() : bar = 1
main() 1 : bar = 123
quork() : bar = 777
quork() : bar = 777
foo() : bar = 2
main() 2 : bar = 124
blark = 0
0 голосов
/ 31 октября 2018

Просто чтобы прояснить для будущих читателей, глобальные и статические переменные не хранятся в памяти кучи или стека.https://www.geeksforgeeks.org/memory-layout-of-c-program/

Они будут храниться либо в инициализированных данных, либо в неинициализированных данных.

Это не основной вопрос, на который ответил dbush, но это неправильное понимание исходного вопроса.

0 голосов
/ 12 сентября 2018

Если существует несколько переменных с одним и тем же именем в нескольких областях, то та, которая находится во внутренней области видимости, является той, которая доступна. Переменные в более широком диапазоне скрыты.

В этом случае account определено в main. Это скрывает переменную с именем account, объявленную в области видимости файла. Тот факт, что внутренняя переменная внутри main объявлена ​​static, не меняет этого.

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

...