根据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
那是我所期望的。
我举了另一个例子,这个例子使用x
和runner()
都可以访问的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
。
此问题顶部的引用是否不正确,是否具有误导性,或者都不是?我是否误解了语义问题?
答案 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
的方式,该访问也不再有效。
#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。