无法理解静态行为

时间:2012-06-27 05:45:44

标签: c++ c

我在

写道
// 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);
}

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

4 个答案:

答案 0 :(得分:9)

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

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

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

但是当您将其更改为int abc(即不使其为static)时,则每个翻译单元都具有相同的对象。如果您在一个文件中更改它,它也会按预期反映在其他文件中。


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

在本网站上搜索翻译单元,您将获得许多主题。阅读它们,然后你就会完全理解它。

答案 1 :(得分:4)

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

  

static变量无法在文件之间共享?

不,他们不可能!这就是让他们static

的目的

static个变量有 internal linkage 。它们的范围仅限于声明它们的翻译单位。如果您想在不同的翻译单元之间共享相同的变量,则应该删除static并使用extern,这会为变量提供 外部链接 ,因此可以看到不同的翻译单元。

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

答案 2 :(得分:4)

当预处理器完成代码后,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,而另一个变量#ifndef __t_h__ #define __t_h__ extern int abc; #endif 无法访问。

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

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

然后将main.c更改为

int abc

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

答案 3 :(得分:1)

在C中,static有两种用法:

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

static int varA;
a.c

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

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

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

由于您在本地变量static上使用了var关键字,因此在返回TheFunction()时此变量不会丢失。

第一次拨打TheFunction()时,您将获得1,第二次拨打TheFunction()时,您将获得2,依此类推。

接下来,让我们看一下C ++中static的用法。

因为任何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 ++中类的静态成员函数。

这四种静态使用方式都是我所知道的,如果还有其他一些用法,请帮助编辑这篇文章,thx:)

修改

添加静态全局功能

1,使用static关键字限制翻译单元中的功能范围。为简单起见,如果您有两个文件:a.cb.c并且您写道:

static void StaticFunction();
<{1>}中的

,因此您只能在a.c中拨打StaticFunction(),如果您想在a.c中调用此功能,则应删除b.c关键字然后在使用前进行delcare。或者只是在statica.h

中的include "a.h"b.c中声明