对“静态”变量的这种定义是否不正确,是否具有误导性,或者两者都不是?

时间:2018-11-16 14:33:20

标签: c scope static lifetime

根据https://www.learn-c.org/en/Static

  

默认情况下,变量在定义变量的作用域内是局部的。 可以将变量声明为静态变量,以将其范围扩大到包含它们的文件。因此,可以在文件内的任何位置访问这些变量。

提供了两个代码示例。
首先,有一个示例,其中在函数int count返回之后,从内存中删除了局部变量runner()

#include<stdio.h>
int runner() {
    int count = 0;
    count++;
    return count;
}

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

输出为:1 1

给出的下一个示例使count变为静态:

#include<stdio.h>
int runner()
{
    static int count = 0;
    count++;
    return count;
}

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

这次的输出是:1 2

在本示例中,

count增加到2,因为在返回runner()时并未将其从内存中删除。
...但是,这似乎与页面开头有关在文件内任何位置访问静态变量的语句无关。这两个示例仅显示static允许count在多次对runner()的调用中保留在内存中(并且每次调用未将其设置为0)。它们不会显示count是否可以在文件内的任何地方访问,因为main()只是打印runner()返回的内容。

为说明我的观点,我举了一个例子,说明static不能使count()在文件内的任何位置都可以访问:

#include<stdio.h>
void runner()
{
    static int count = 0;
    count++;
    return;
}

int main()
{
    runner();
    printf("%d ", count);
    runner();
    printf("%d ", count);
    return 0;
}

输出为:

prog.c: In function 'main':
prog.c:12:23: error: 'count' undeclared (first use in this function)
         printf("%d ", count);
                       ^
prog.c:12:23: note: each undeclared identifier is reported only once for each function it appears in

那是我所期望的。

我举了另一个例子,这个例子使用xrunner()都可以访问的main()

#include<stdio.h>
int x = 0;
void runner()
{
    static int count = 0;
    count++;
    x = count;
    return;
}

int main()
{
    runner();
    printf("%d ", x);
    runner();
    printf("%d ", x);
    return 0;
}

输出为:1 2

此问题顶部的引用是否不正确,是否具有误导性,或者都不是?我是否误解了语义问题?

4 个答案:

答案 0 :(得分:2)

您是正确的,引用是错误的。在功能块static中声明变量会增加其生存期,而不是其作用域。 (作用域是您可以使用名称的代码部分。)

我真的无法想象一种正确的方式来解释“在文件内的任何地方访问”。如果您有一个指向此类变量的指针,则可以在其他函数中取消对该指针的引用,但这对所有函数都是正确的,而不仅仅是在同一文件中。

大概是时候停止使用该网站了。

答案 1 :(得分:2)

该教程非常混乱,需要从Internet上删除。


C有两个不同但相关的术语:作用域存储持续时间。范围指定可以通过其名称访问变量的位置。存储期限指定了变量将其值保留多长时间。

在您的前两个示例中,您根本没有更改变量的范围,而是更改了其存储时间。

作用域保持不变:变量具有函数 WebDriverWait wait = new WebDriverWait(driver, 20); WebElement link = driver.findElement(By.xpath("//a[@class='mat-listed-item ng-star-inserted' and contains(@href, 'users')]")); WebElement div = link.findElement(By.xpath(".//div[@class='mat-list-item-content']")); WebElement goToUser = wait.until(ExpectedConditions.elementToBeClickable(div)); goToUser.click(); 的局部作用域,并且不能通过该函数外部的名称进行访问。关键字int runner()不影响范围。

但是,您可以更改存储期限。所有static变量都具有(毫不奇怪)静态存储持续时间,这意味着它们将在程序的整个执行过程中保持其内容有效。这就是为什么函数在第二次调用时会记住该值的原因。

最后,为了解决本教程的进一步误解,还有一个术语叫做 linkage ,它也与范围有关。带有内部链接的变量绝对可以在声明它们的.c文件(以及该.c文件中所有包含的.h文件)中访问。

其中带有外部链接的变量可以在整个程序中使用关键字static进行显式访问。您不能将内部和外部链接结合在一起-并且所有声明为extern的变量都将获得内部链接。这意味着您将无法从其他.c文件访问它们。

通过声明变量static,您可以为其指定静态存储期限和内部链接。

函数的作用域和链接与变量遵循相同的规则,除了存储持续时间对函数没有意义。

答案 2 :(得分:1)

TL; DR -具有静态存储空间的变量在程序的整个执行过程中均有效,对其进行的任何访问均有效。是否可以从任何部分访问取决于定义的作用域

因此,为了回答标题:我同意,这是一种误导,但与此同时,我将添加更多上下文,以详细说明尝试传达的实际消息。


您已经有了答案,只需加上我的两分钱(使用标准中的权威字眼):

static是存储类别说明符,它有助于确定存储持续时间。

引用C11,第6.2.4章

  

对象的存储期限决定其寿命。 [....]

然后

  

对象的生存期是程序执行期间存储空间的一部分   保证为其保留。一个对象存在,具有恒定的地址, 33)并保留   它在整个生命周期中的最后存储值。 [...]

因此,对于具有静态存储持续时间的变量,

  

一个其标识符声明为没有存储类说明符的对象   _Thread_local,并且具有外部或内部链接或与存储类   说明符static具有静态存储期限。它的生命周期是   程序及其存储值在程序启动之前仅初始化一次。


'nuff talk,给我看一下codez:

为了比较,让我们看一下代码片段:

  • 代码段一:无效的代码
#include<stdio.h>
char *func()
{
    char arr [ ] = "Hello!";
    return arr;
}

int main()
{        
    printf("%s ", func()); // you're accessing `arr`, some or other way!!
    return 0;
}

在这里,返回的指针指向无效的内存,就像在函数调用结束时一样,自动局部变量arr被销毁(生命周期终止),并且返回的地址现在指向无效的内存。

因此,即使您有访问arr的方式,该访问也不再有效。

  • 代码段2:有效代码
#include<stdio.h>
char *func()
{
    static char arr [ ] = "Hello!";
    return arr;
}

int main()
{        
    printf("%s ", func()); // you're accessing `arr`, some or other way!!
    return 0;
}

这是一个非常有效的代码,因为静态存储持续时间,它使arr可以在其定义范围之外“访问”。

答案 3 :(得分:1)

报价使范围寿命混乱。

变量的作用域描述了可以通过名称​​ 访问变量的位置。变量或更确切地说是对象生存期描述了对象何时有效。对于非静态局部变量,其作用域和生存期都是在其定义的块。

在您的示例中,在static的情况下,其范围仍然是封闭的块,但其生存期是整个程序的生存期。这意味着您可以返回static变量的地址,并取消对该地址的引用是有效的。例如:

#include<stdio.h>
int *runner()
{
    static int count = 0;
    count++;
    return &count;    // ok, count has full program lifetime
}

int main()
{
    int *p = runner();
    printf("%d ", *p);
    p = runner();
    printf("%d ", *p);
    return 0;
}

输出:

1 2

但是,如果您尝试使用非静态变量执行此操作:

#include<stdio.h>
int *runner()
{
    int count = 0;
    count++;
    return &count;    // BAD: count no longer exists when function returns
}

int main()
{
    int *p = runner();
    printf("%d ", *p);   // UNDEFINED BEHAVIOR
    p = runner();
    printf("%d ", *p);   // UNDEFINED BEHAVIOR
    return 0;
}

您通过使用指向不再存在的对象的指针来调用undefined behavior