【问题标题】:Not able to understand static behaviour无法理解静态行为
【发布时间】:2012-06-27 05:45:43
【问题描述】:

我写在

// In file t.h

#ifndef __t_h__
#define __t_h__
static int abc;
#endif

--

//In   main.c
    #include <stdio.h>
    #include "t.h"
    int main()
    {
        abc++;printf("%d \n", abc);
        test();
    }

--

//In test.c

#include <stdio.h>
#include "t.h"

void test()
{
    abc++;
    printf("%d \n", abc);
}

当我运行该项目时,我发现了abc is 1 and 1output。 但是当我在t.h 中将其更改为int abc 时。 abc = 1 and 2 的输出。 为什么当控件到达test.c 文件时静态不保留该值。 如果它不保留,那么为什么不提供static variable can not be shared between/among 文件的错误?

【问题讨论】:

  • 我建议您阅读有关 C 基础知识的更多信息,尤其关注变量和变量的生命周期/可见性/链接,以及 static 关键字的实际含义。

标签: c++ c


【解决方案1】:

static 变量具有内部链接,这意味着每个翻译单元都有自己的副本。

因此,在您的程序中,每个包含t.h.cpp 文件都有自己的静态变量副本,这反过来意味着,有两个 对象记忆。您可以尝试打印他们的地址以确认这一点,因为它们会有所不同。

这使情况变得非常简单:如果您更改一个.cpp 中的对象,它不会反映在另一个.cpp 文件中,因为另一个.cpp 文件中的对象是一个不同的 对象。为什么要改变?

但是当你把它改成int abc(即不要改成static),那么每个翻译单元都有相同的对象。如果您在一个文件中更改它,它也会按预期反映在其他文件中。


至于共享,那么是的,static 对象可以在同一个翻译单元中的两个函数之间共享,但它们不能在两个翻译单元之间共享。

在本站搜索翻译单元,你会得到很多关于它的话题。阅读它们,您就会完全理解。

【讨论】:

  • 这不是共享变量吗?根据stackoverflow.com/questions/1045501/…
  • @RasmiRanjanNayak:“共享变量”是什么意思? 什么之间的共享?静态对象可以在同一个翻译单元中的两个函数之间共享,但它们不能在两个翻译单元之间共享。
  • @Rasmi - extern intstatic int 之间存在巨大的差异。一个是共享的,一个是不共享的。
  • @BoPersson:你能详细说明一下吗?
  • @RasmiRanjanNayak:static int a 声明了一个具有内部链接的变量,而extern int a 声明了一个具有外部链接的变量。在这个论坛上搜索这些术语(internalexternal 链接),你会得到数百个主题。
【解决方案2】:

当预处理器处理完您的代码后,main.c 看起来像

// omitted stuff from stdio
static int abc;
int main()
{
    abc++;printf("%d \n", abc);
    test();
}

test.c 看起来像

// omitted stuff from stdio
static int abc;
void test()
{
    abc++;
    printf("%d \n", abc);
}

因此,每个文件都包含自己的变量abc,其他文件无法访问。

一种解决方案是将 t.h 更改为

#ifndef __t_h__
#define __t_h__
extern int abc;
#endif

然后把 main.c 改成

#include <stdio.h>
#include "t.h"
int abc;
int main()
{
    abc++;printf("%d \n", abc);
    test();
}

你可以这样想:你的程序中现在只有一个 int abc,在 main.c 但 test.c 知道它的存在,因为 extern int abc 告诉 test.c 在项目的其他地方是一个名为abc 的整数,它将能够在链接时找到。

【讨论】:

    【解决方案3】:

    当您在头文件中声明static 变量时,会在包含头文件的每个Translation unit 中创建静态变量的副本。因此,您的程序中涉及的每个翻译单元现在都有自己的 abc 副本,因此您会得到观察到的行为。该行为不是您所期望的,而是定义明确的。

    static变量不能在文件之间共享?

    不,他们不可能!这就是制作它们的目的static

    static 变量具有 internal linkage。它们的范围仅限于声明它们的翻译单元。它们无法在 TU 之外访问。如果您想在不同的翻译单元之间共享相同的变量,您应该删除 static 并使用 extern,这会为变量提供外部链接 ,因此在不同翻译单元中的可见性。

    好读:
    How do I use extern to share variables between source files?

    【讨论】:

    • 您无法访问外部静态变量;它们的符号不会在链接时导出。
    • @lvella:没有什么叫做外部静态变量。可以是外部变量,也可以是静态的,不能两者兼有。
    • 由于我所说的原因,可能无法声明/使用外部静态变量(它们不可访问,因此制定了语言规范来禁止它),但从概念上讲并没有错该声明。此类变量是模块中的静态变量,与您所指/工作的模块不同。
    • @lvella:我看不出重点。static 有内部链接,extern 有外部链接,所以很明显,拥有static extern 没有任何意义变量。出于同样的原因,语言规范禁止它。
    【解决方案4】:

    在 C 中,static 有两种用法:

    1、使用static关键字来限制var在翻译单元中的作用域。为了简单起见,如果您有两个文件:a.cb.c,并且您写道:

    static int varA;
    

    a.c中,那么这意味着varA只能在a.c中使用,如果要在b.c中使用varA,则应删除static关键字,并添加extern int varA;b.c中,人们通常做的是我们创建另一个名为:a.h的文件,并在a.h中写入extern int varA;,我们只需在include "a.h"中写入include "a.h"b.c,这样我们就可以写入我们想要的每个变量extern in a.h 并使用单个 include "a.h" 使这些变量或函数在其他 .c 文件(即源文件)中合法

    2、在函数中使用static定义local variable,例如:

    int TheFunction()
    {
      static int var = 0;
      return ++var;
    }
    

    因为您在局部变量var 上使用了static 关键字,所以返回TheFunction() 时该变量不会丢失。

    第一次调用TheFunction(),你会得到1,第二次调用TheFunction(),你会得到2,以此类推。

    接下来,让我们看看静态在 C++ 中的用法。

    因为任何 C++ 编译器都可以编译 C 代码,所以上面的 2 个用法也在 C++ 中。

    另外两种用法是: 1、静态成员变量。 2、静态成员函数。

    让我们直接看代码:

    #include <iostream>
    
    using namespace std;
    
    
    class Test
    {
    public:
        Test() : m_nNormalVar(0)
        {
    
        }
    public:
        // You need to init this static var outside the class
        // using the scope operator:
        // int Test::m_nStaticVar = 0;
        static int m_nStaticVar;
    
        // You can init this const static var in the class.
        const static int m_nConstStaticVar = 10;
    
        // This is just a normal member var
        int m_nNormalVar;
    };
    int Test::m_nStaticVar = 0;
    
    int main(int argc, char *argv[])
    {
        Test a;
        Test b;
        a.m_nStaticVar++;
        a.m_nNormalVar++;
        cout << b.m_nStaticVar << endl;
        cout << b.m_nNormalVar << endl;
    
        return 0;
    }
    

    ab 是类Test 的对象,它们具有相同的m_nStaticVar 和相同的m_nConstStaticVar,但它们有自己的m_nNormalVar 这是一个静态成员变量。

    #include <iostream>
    
    using namespace std;
    
    
    class Utility
    {
    public:
        // This is a static member function, you don't
        // need to have a concrete object of this class
        // to call this function.
        static int SelectMax(int a, int b)
        {
            return a > b ? a : b;
        }
    };
    
    int main(int argc, char *argv[])
    {
        // No objects of class Utility
        cout << Utility::SelectMax(2, 1) << endl;
    
        return 0;
    }
    

    所以这是 C++ 中类的静态成员函数。

    static的这四种用法我都知道了,如果还有其他用法,请帮忙编辑本帖,thx:)

    编辑:

    添加静态全局函数

    1、使用static关键字限制函数在翻译单元中的作用域。为了简单起见,如果您有两个文件:a.cb.c,并且您写道:

    static void StaticFunction();
    

    a.c中,所以只能在a.c中调用StaticFunction(),如果你想在b.c中调用这个函数,你应该去掉static关键字,然后在使用前删除它。或者只是在a.hinclude "a.h"b.c 中声明它

    【讨论】:

    • -1:“将在全局堆栈上分配” - 抱歉没有全局堆栈。这本质上是静态变量。加堆栈。你怎么能调用这个堆栈???
    • @KirillKobelev 删除了全局堆栈部分
    • 如果区分静态成员字段和静态成员函数,还应该说静态全局函数(而不仅仅是静态全局变量)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 2012-11-07
    • 2020-01-02
    相关资源
    最近更新 更多