gpt4 book ai didi

c - 何时在 C 中将局部变量声明为静态变量?

转载 作者:太空狗 更新时间:2023-10-29 16:12:40 25 4
gpt4 key购买 nike

我最近学习了 C 中的存储类。特别是我对 static 存储类着迷。来自 Haskell,我避开了将输出缓冲区传递给函数以获得结果的概念。例如考虑以下 readfile 函数:

#include <stdio.h>

void readfile(const char * filename, char * contents, size_t size) {
FILE * file = fopen(filename, "rb");
fread(contents, size, 1, file);
contents[size] = 0;
fclose(file);
}

我不喜欢这样的代码有几个原因:

  1. 使用 void 作为返回类型让我感到厌烦。我不知道为什么。就是这样。
  2. 将输出缓冲区传递给函数似乎不自然。可变状态容易出错。
  3. 您不必将要读取的字节数作为输入参数传递给函数。
  4. 您需要手动创建缓冲区并预测文件的大小。

由于这些问题我重写了上面的代码如下:

#include <stdio.h>
#include <malloc.h>

char * readfile(const char * filename) {
FILE * file = fopen(filename, "rb");

fseek(file, 0, SEEK_END);
size_t size = ftell(file);
fseek(file, 0, SEEK_SET);

static char * contents;
contents = malloc(size + 1);
fread(contents, size, 1, file);
fclose(file);

contents[size] = 0;
return contents;
}

现在读取文件内容所需要做的就是将文件名传递给readfile。它为文件的内容分配空间并返回指向新创建的缓冲区的指针。您唯一需要做的簿记工作是在使用完缓冲区后释放缓冲区。

正如您在上面的代码中所看到的,我已将 contents 声明为 static 以便该变量只有一个实例,这样您就可以在没有编译器给你一个警告。在我看来,这是比使用全局变量更简洁的解决方案。

尽管如此,我对在生产代码中使用 static 持怀疑态度:部分原因是我担心可变状态与共享变量的结合,部分原因是这是我第一次使用它。如前所述,使用 static 有哪些潜在风险?

例如,当您同时读取两个文件时,上面的代码会不会给出错误的结果?如何在不返回到 C 风格代码的情况下解决这些问题(例如,将输出缓冲区传递给函数等)

最佳答案

在 C 中,您几乎不想将局部变量声明为 static

使变量成为static 本质上使它成为一个全局变量,其名称在该函数之外是不可访问的。您可能很清楚,全局变量可能会产生问题:如果您从两个不同的线程运行 readfile,您可能会先调用 malloc 并将结果存储到contents,第二个线程调用malloc并将它的结果存储到contents,然后第一个线程 fread 到第二个线程分配的 contents 中,如果第二个线程上读取的文件较小并且在任何情况下都是不希望的,这可能会导致缓冲区溢出。

您可能想使用 static 的原因是 contents 以前是一个数组。如果是这样,编译器会正确地警告您不能将其返回给调用者:它将分解为一个指针,但是一旦函数返回,局部数组变量就会被破坏并且指针变得无效。将其声明为 static 使其有效返回,因为它是一个全局变量,当函数退出时它不会被销毁并且指针将保持有效。但是,如果将它与线程一起使用,仍然存在问题。

您唯一可能想要使用 static 的情况是您有一些仅在函数中使用的常量数据。例如:

static const int some_integers[] = { 1, 2, 3, 4 };

然后你可以节省一些堆栈空间。

以免我忘记提及您的具体代码,删除 static 可使其按预期工作。如果要在现实生活中使用此代码,我会确保添加一些错误检查,因为您调用的几乎所有函数都可能失败,并且只会通过返回值发出信号。

关于c - 何时在 C 中将局部变量声明为静态变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21656585/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com