static 关键字是不是影响范围?

Posted

技术标签:

【中文标题】static 关键字是不是影响范围?【英文标题】:Does the static keyword affect scope?static 关键字是否影响范围? 【发布时间】:2016-10-11 16:41:26 【问题描述】:

在 C89 中,static 关键字会影响作用域吗?

我的软件负责人告诉我:

“在文件顶部标记为静态的变量在技术上不再具有全局范围。静态是范围限定符以及存储关键字。范围是 涵盖符号可见性的概念,尽管可见性是 自动编译以具有内在关联的存储持续时间 几乎所有语言。我的意思是你不能命名一个范围 这也没有定义 C/C++ 中的存储持续时间。表达 范围不是用户定义的,并且在 l-param 和 r-param 涵盖的 C/C++ 中 块作用域在 C/C++ 中由用户定义的主体完全词法化 范围在 C/C++ 中完全由用户定义的主体和 声明文件范围在 C/C++ 中技术上不存在,因为 全局变量和模块范围根据词典模块范围接管 是在 C/C++ 中使用 static 定义的关键字,其他范围词典更改 访问规则,但可见性仍然基于模块 Global 当没有其他范围适用时,范围是 C/C++ 中的默认值,并且是 词法由 extern 关键字控制问题是静态是 不仅仅是作为关键字的范围限定符。它是一个范围限定符和 记忆关键字。”

我很困惑。我一直认为静态与翻译单元之间的可见性和变量的存储持续时间有关。两者都与范围无关。不是这样吗? C++ 中的静态/作用域关系是否不同?

【问题讨论】:

“模块”? C 没有模块。 我为你们的团队感到非常抱歉。这个人显然不知道他/她在说什么。我也不会使用 C89 来教 C。 是的,static 关键字在 C 语言中有两个不同的用途。这似乎是这个家伙唯一正确的地方。他像这样使用“C/C++”的次数意味着某事是一个很好的线索。 C 中没有“全局范围”之类的东西。文件范围是您可以拥有的最大范围,因此static 不会影响符号的范围。它会影响存储时间和链接。 听起来您的软件主管和您一样困惑,并且正在大喊大叫,以使他看起来像是知道自己在说什么。 没有语言“C/C++”。如果您的领导不知道这一点并掩盖差异,那么她肯定处于错误的位置。他似乎也混淆了联系、范围和寿命。顺便说一句,什么是“内存关键字”?我没有发现这是标准。 【参考方案1】:

在文件顶部标记为静态的变量在技术上不再具有全局范围。

“全局范围”不是 C 中存在的概念。正确的术语是 文件范围。在 C++ 中,存在一个类似的概念,称为 全局命名空间。看来加班的人把这两个词结合起来了。

Static 是一个作用域限定符,也是一个存储关键字。

static 不是范围限定符,它是存储类说明符。 static 可以影响链接和存储持续时间,但不会影响范围。

范围是一个涵盖符号可见性的概念,尽管可见性会自动编译为具有本质上与存储持续时间相关的 几乎所有语言。

作用域与符号的可见性无关(在链接器意义上)。 Linkage 确实如此(因此它被称为 linkage)。第二个子句是胡言乱语。

我的意思是你不能命名一个不定义 C/C++ 中存储持续时间的范围。

这句话也没有意义。考虑块范围内的局部静态变量。即使块范围定义了自动存储变量,它也具有静态存储持续时间。

表达式范围不是用户定义的,在 C/C++ 中被 l-param 和 r-param 覆盖

“表达式范围”没有意义。 “l-param”和“r-param”也是无意义的词。

跳过关于“词法”和“模块”的部分,因为它是零意义的。

问题在于 static 不仅仅是作为关键字的范围限定符。它是一个作用域限定符和一个内存关键字。

同样,static 与范围或内存无关。使用这种过于简单的解释基本上忽略了存储持续时间、范围和初始化的所有其他方面,所以它只是简单地不起作用。

【讨论】:

我喜欢这个答案。【参考方案2】:

C11 标准的第 6.2.1 节定义了“范围”的含义:

对于标识符指定的每个不同实体,标识符仅在称为其范围的程序文本区域内可见(即可以使用)。由同一标识符指定的不同实体要么具有不同的范围,要么位于不同的名称空间中。作用域有四种:函数、文件、块和函数原型。 (函数原型是声明其参数类型的函数的声明。)

C89/90 规范的第 3.1.2.1 节几乎相同:

标识符仅在区域内可见(即可以使用) 程序文本称为其范围。范围有四种: 函数、文件、块和函数原型。 (一个函数原型 是声明其类型的函数的声明 参数。)

因此,不存在 global 范围,至少就 C 标准而言。在任何函数或块之外定义的标识符具有 file 范围,static 的存在与否对此没有影响,仅对符号的 链接 有影响,即完全不同的东西(但您的潜在客户可能会将其与“范围”一词混淆或混淆)。

【讨论】:

static 不影响链接的一种情况是 C++ 中的类数据成员。 @user6412786:在大多数情况下,它不会影响链接——它所做的一个地方是文件范围内的标识符。【参考方案3】:

你的线人很困惑。 static 对范围没有任何影响。

文件范围用词不当,因为您可以使用#include 指令或其他假设的依赖于实现的工具来构建多文件翻译单元。全局范围也是用词不当,因为一个程序可以由多个翻译单元组成。模块仍然不是语言的一部分。

static 可以影响链接,但这是与作用域不同的概念。

【讨论】:

“文件范围”不是用词不当。它被 C 标准明确使用。 “全局范围”在非正式演讲中可以互换使用,但 C++ 标准明确提到“全局命名空间”。除非您暗示 C 和 C++ 标准让他们感到困惑,否则我也不会称他们为误称。 第 2 部分:一个翻译单元存在“文件”或“全局”范围。 “#include”是一个复制/粘贴操作,它是翻译单元的部分。参见 2.1 C++中的“单独翻译”。 @user6412786:我知道 C 标准使用术语“文件范围”,但它是根据翻译单元而不是文件正式定义的,所以是的,我相信这个术语是用词不当。 (诚​​然,“翻译单元范围”会很麻烦。)正如您所说,C 从不指代全局范围,有些使用该术语的人实际上对全局可能意味着什么感到困惑。事实上,这里证明的范围和可见性之间的混淆就是一个例子。标准 w.r.t 没有混淆。 “全局命名空间”;该命名空间实际上是全局的,通常使用名称修饰来实现。【参考方案4】:

关键字static 在C 中有多种用途。例如,在顶部的C 源文件中,您可能有:

#include <stdio.h>
//  .. other includes and comments and stuff

int  globallyVisibleInt = 0;    // a variable that other compilation units can see
static int fileVisibleInt = 0;  // a variable visible in the file from this point

变量fileVisibleInt 是在应用程序加载时创建和初始化的,但是如果您尝试从其他编译单元访问它,则在尝试链接时会收到来自链接器的错误。

您还可以在函数中使用static 来创建将存在并保持状态的变量。

int myFunc (int k)

    static int mySavedInt = 0;   // create and initialize a permanent int variable

    if (k > 10) 
        mySavedInt = k;  // use the variable to save a value for the next time function is called
     else if (mySavedInt > 22) 
        // do some stuff
    

static 变量对文件中的其他源可见的点是它出现在源文件中的点,它的可见性由各种范围规则控制。例如,在函数中定义的static 仅在该函数中可见,或者如果static 用于其他一些更缩小的范围,例如iffor,那么它是一个永久变量,即仅在该范围内可见。

有各种常用的短语,但不一定在技术上准确或您可以在标准中找到。例如,短语“全局范围”对我来说意味着该事物在编译单元之外是可见的。通过“模块”,我将承担功能。对于大多数日常活动来说,语言的松散性就可以了。

在 C++ 中,static 可能会有很大不同,具体取决于您是使用 C++ 构造(例如 class)还是使用 static 作为方法和成员的限定符,或者您使用的是旧的 C 方式.

另见:

File Scope and Global Scope: C & C++.

Why file scope static variables have to be zero-initialized?

Dr. Dobbs: Scope Regions in C++.

【讨论】:

以上是关于static 关键字是不是影响范围?的主要内容,如果未能解决你的问题,请参考以下文章

弃用 static 关键字...不再?

弃用 static 关键字...不再?

java static 详解

简述static关键字void与void *(void指针)函数指针

Java基础--static关键字

static 和 final 关键字 对实例变量赋初始值的影响