Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C语言中的内部静态变量,您会使用它们吗?_C_Static - Fatal编程技术网

C语言中的内部静态变量,您会使用它们吗?

C语言中的内部静态变量,您会使用它们吗?,c,static,C,Static,在C语言中,外部静态变量可以在文件中的任何位置查看,而内部静态变量只能在函数中看到,但是持久的 例如: #include <stdio.h> void foo_bar( void ) { static counter = 0; printf("counter is %d\n", counter); counter++; } int main( void ) { foo_bar(); foo_bar();

在C语言中,外部静态变量可以在文件中的任何位置查看,而内部静态变量只能在函数中看到,但是持久的

例如:

#include <stdio.h>

void foo_bar( void )
{
        static counter = 0;
        printf("counter is %d\n", counter);
        counter++;
}
int main( void )
{
        foo_bar();
        foo_bar();
        foo_bar();
 return 0;
}

我的问题是为什么要使用内部静态变量?如果您不希望静态变量在文件的其余部分可见,那么函数是否真的应该在它自己的文件中?

我认为人们通常远离内部静态变量。我知道strtok()使用了一个或类似的函数,因此它可能是C库中最讨厌的函数


像C#这样的其他语言甚至不支持它。我认为,在OO语言出现之前,它曾经是为了提供某种封装的外观(如果你可以这样称呼它的话)

它们用于实现strtok之类的工具,并且会导致重入问题


在使用这个工具之前仔细思考,但有时它们是合适的。

< P>一个简单的用法是函数可以知道它被调用了多少次。

在C中可能不是非常有用,但是它们在C++中被用来保证命名空间范围静态的初始化。在C和C++中,在多线程应用程序中都存在问题。

< P>,例如,在C++中,它被用作获取单点Is/P>的一种方式。
SingletonObject& getInstance()
{
  static SingletonObject o;
  return o;
}
用于解决初始化顺序问题(尽管它不是线程安全的)

Ad“函数不应该在它自己的文件中吗?”

当然不是,那是胡说八道。编程语言的主要目的是促进代码的隔离和重用(局部变量、过程、结构等都可以做到这一点),这只是实现这一点的另一种方法


顺便说一句,正如其他人指出的,几乎所有反对全局变量的论点也适用于静态变量,因为它们实际上是全局变量。但是在很多情况下,使用globals是可以的,人们也是这样做的。

我不希望静态变量的存在迫使我将函数放入它自己的文件中。如果我有许多类似的函数,每个函数都有自己的静态计数器,我想把它们放在一个文件中,会怎么样?我们必须做出足够多的决定来决定将东西放在何处,而不需要更多的约束。

一些静态变量的用例:

  • 您可以将其用于计数器,并且不会污染全局命名空间
  • 您可以使用一个函数来保护变量,该函数将值作为指针获取并返回内部静态值。这是您可以控制如何分配值的方式。(如果只想获取值,请使用NULL)

我从未听说过这种被称为“内部静态变量”的特殊结构。我想这是一个合适的标签

与任何构造一样,它必须以知识和负责任的方式使用。您必须知道使用构造的后果

Public Function GetTempFileName() As String
  Static i As Integer = 0
  i += 1
  Return String.Format("Temp{0}", i.ToString("00000"))
End Function
它保持在最局部范围内声明的变量,而不必为函数创建单独的文件。它还阻止全局变量声明

比如说-

char *GetTempFileName()
{
  static int i;
  char *fileName = new char[1024];
  memset(fileName, 0x00, sizeof(char) * 1024);
  sprintf(fileName, "Temp%.05d.tmp\n", ++i);
  return fileName;
}
VB.NET支持相同的构造

Public Function GetTempFileName() As String
  Static i As Integer = 0
  i += 1
  Return String.Format("Temp{0}", i.ToString("00000"))
End Function

由此产生的一个后果是,这些函数不再是可重入的,也不再是线程安全的。我在多线程环境中看到或听到过函数局部静态变量的结果,但它并不漂亮。

我发现它对于一次性延迟初始化非常方便:

int GetMagic()
{
   static int magicV= -1;

   if(-1 == magicV)
   {
      //do expensive, one-time initialization
      magicV = {something here}
   }
   return magicV;
}

正如其他人所说,在第一次调用时,这不是线程安全的,但有时您可以侥幸逃脱:)

这种混淆通常是因为
static
关键字有两个用途

在文件级使用时,它控制编译单元外对象的可见性,而不是对象的持续时间(可见性和持续时间是我在教育课程中使用的外行术语,ISO标准使用了不同的术语,您可能希望最终了解这些术语,但我发现它们会让大多数初学者感到困惑)

在文件级别创建的对象的持续时间已经决定,这是因为它们处于文件级别。然后,
static
关键字只会使链接器看不到它们

在函数内部使用时,它控制持续时间,而不是可见性。可见性已经确定,因为它在函数内部-在函数外部看不到它。在本例中,
static
关键字使对象与文件级对象同时创建

注意,技术上,函数级静态可能不一定存在直到函数被首次调用(并且它对于C++具有它的构造函数可能是有意义的),但是我所使用的每一个C实现都在文件级对象的同时创建它的函数级静态。 <>也,当我使用“对象”这个词时,我并不是C++对象的意思(因为这是一个C问题)。这只是因为

static
可以应用于文件级别的变量或函数,我需要一个包罗万象的词来描述它

函数级静态仍然被大量使用——如果多线程程序不能满足这一要求,它们可能会给多线程程序带来麻烦,但是,如果您知道自己正在做什么(或者您没有执行线程),它们是在多个函数调用中保持状态的最佳方法,同时仍然提供封装

即使使用线程,也可以在函数中使用一些技巧(例如在函数中分配特定于线程的数据),以使函数在不必要地公开函数内部的情况下工作

我能想到的唯一其他选择是全局变量和每次向函数传递“状态变量”


在这两种情况下,您将函数的内部工作公开给它的客户机,并使函数依赖于客户机的良好行为(始终是一个危险的假设)。

所有静态都是持久的,并且
void errorLog(...)
{
    static int reentrant = 0;
    if(reentrant)
    {
        // We somehow caused an error while logging a previous error.
        // Bail out immediately!
        hardwareReset();
    }

    // Leave ourselves a breadcrumb so we know we're already logging.
    reentrant = 1;

    // Format the error and put it in the log.
    ....

    // Error successfully logged, time to reset.
    hardwareReset();
}