选择“静态于全局”。为什么?

时间:2018-09-12 15:20:18

标签: c static global-variables

以下代码的输出为0。

int account=2;

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

为什么选择静态变量而不是全局变量?因为我了解的是全局变量和静态变量都存储在堆中,而不是存储在函数堆栈中,对吗?那么,它使用什么方法来选择一个呢?

5 个答案:

答案 0 :(得分:25)

如果在多个作用域中存在多个具有相同名称的变量,则最内部作用域中的一个是可访问的变量。较高范围的变量被隐藏。

在这种情况下,您在account中定义了main。这将隐藏在文件作用域声明的名为account的变量。 main内部的内部变量被声明为static的事实并不会改变这一事实。

在局部变量上使用static声明时,意味着它通常与全局变量存储在同一位置,当名称相同时,它与可见变量无关。

答案 1 :(得分:7)

考虑这个小小的自我解释程序:

#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

答案 2 :(得分:3)

为便于将来的读者澄清一下,全局和静态变量未存储在堆或堆栈内存中。 https://www.geeksforgeeks.org/memory-layout-of-c-program/

它们将存储在初始化数据或未初始化数据中。

那不是dbush回答的主要问题,但这是对原始问题的误解。

答案 3 :(得分:2)

简短的回答:封装。

static描述了变量的生存期可见性,其含义根据上下文而变化。我认为这是c中封装的更有用和重要的语言功能之一。忽略与extern的复杂关系,这是一个简化的描述:

在文件级别定义的

static变量具有程序生存期和 compilation unit 可见性。这意味着.c文件中的所有函数都可以访问/修改变量,但其他.c文件则不知道该变量。 super 对于确保跨一个编译单元的函数中使用的变量不会意外链接到其他编译单元中的变量很有用。就个人而言,我高度建议默认情况下将所有文件变量设置为静态。仅在您确实希望另一个编译单元可以访问它时才删除static说明符(尽管getter函数可能更安全)

在块作用域(最重要的是函数作用域)内的static 中声明的变量具有程序寿命和作用域可见性。这意味着它的功能就像您在文件中全局声明了变量一样,但是只有该块范围内的代码才能看到它。这也意味着从一个调用到下一个调用,变量不会被破坏,状态可以在一次调用之间转移。

静态变量的一个真正重要的区别是它们默认初始化为零。这与c中的 all 其他变量不同,这是您的程序将值打印为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;
}

希望您可以通过这种模式看到将变量放置在函数中并执行可选操作(例如获取互斥锁以分配内存)来保护变量。您甚至可以通过这种方式实现double-lock pattern

我暗中希望所有C ++程序员都学习良好的c封装,因为实际上该语言确实鼓励它。通过仅将需要相互通信的功能放在编译单元中,您可以做大量工作。在非OOP语言中,这可能非常强大。

有关静态和外部的详细信息,请参见https://en.cppreference.com/w/c/language/storage_duration

答案 4 :(得分:0)

为什么要使用最里面的变量,这是一种务实的推理:您并不总是控制代码之外的内容。您希望能够编写一个肯定有效的函数。如果其他程序员(例如,在较大的团队中)可以仅仅通过他们在代码其他部分中命名变量的方式来破坏您的代码,那么与现在相比,编程会更加痛苦。