C:如何声明一个返回非静态字符串的静态函数?

时间:2015-01-30 19:42:43

标签: c function-prototypes

如果函数声明为

static char *function(...) { ... }

这是否意味着这是一个返回static char *的非静态函数,或者是一个返回非静态char *的静态函数?

比较以下两个功能。哪一个是正确的用途?

static char *fn1(void)
{
  static char s[] = "hello";
  return s;
}


static char *fn2(void)
{
  char *s = malloc(6);
  strcpy(s, "world");
  return s;
}

4 个答案:

答案 0 :(得分:8)

static适用于函数,而不适用于其返回类型。这两个功能都是正确的 - 区别在于s首次拨打fn1时会初始化一次,而fn1的所有来电都会共享s;而在fn2中,每次通话都会分配一个新的s。由于fn1fn2都有static个链接,因此它们对于定义它们的翻译单元(大约是源文件)是私有的。

答案 1 :(得分:3)

你的两个函数定义都是正确的。

需要注意的是,static这里用于将函数限制为文件范围,而不是指定返回类型,即,此函数可以由同一文件中存在的其他函数[调用]使用,但不是通过其他文件中存在的函数,尽管它们可能已被编译并链接在一起形成二进制文件。

答案 2 :(得分:3)

static在函数应用于函数之前,而不是它的类型(或者甚至是它的一部分,如返回类型):
这意味着该函数具有静态链接,也就是翻译单元/文件本地(因此很可能被内联)。

这两个函数都是正确的,尽管它们有不同的语义:

  • 第一个返回指向静态数组的指针,其内容可能会被修改。如果你这样做,请注意并发和重入问题。
  • 第二个分配一些堆内存,用字符串初始化它,然后返回它。请记住free它。

答案 3 :(得分:1)

与函数定义一起使用时,static关键字表示该函数具有文件级范围。这意味着函数名称仅在文件本身中可见。函数定义中使用的static关键字修改函数名称可见性,不修改函数返回类型。

因此声明为static的函数可以返回任何类型的函数。

在函数体中定义的变量上使用static用于指示在加载和启动应用程序时创建变量。因此,如果对函数中的变量使用static修饰符,则在调用函数时不会在堆栈上创建该变量。它独立于调用函数时存在。但是,变量的可见性仅在函数内。

在您的示例中,您有一个返回static变量地址的函数。你可以这样做,但你必须明白这个用途不是线程安全的。换句话说,调用该函数的所有线程将在相同的内存位置获取相同的变量,而不是它们自己的变量版本。

您还必须明白,如果您返回static变量的地址,也会导致重入和递归问题。原因是堆栈上的变量提供了重入和递归,因为每次调用函数时,都会向堆栈添加一个新帧,因此每个函数调用都有自己的堆栈帧,因此它有自己的变量集。

这是标准C库中旧strtok()函数的已知问题,它使用strtok()函数中的变量来维护调用之间的状态,使用NULL作为最后一个字符串的地址解析字符串时调用strtok()。我已经看到一个问题,一个名为strtok()的函数开始解析一个字符串,然后调用另一个函数,该函数又调用strtok()来开始解析一个不同的字符串。结果是一些非常奇怪的错误和行为,直到找到原因。

在文件中的全局变量上使用static修饰符将创建一个可由文件中的多个函数共享的全局变量。但是,如果在函数名称上使用static修饰符,static变量将只具有文件范围可见性。

// .. top of a file of C source code

static int aStaticInt = 0;  // a static int that can be shared by all functions in the file but is visible only in the file
int aNonStaticInt = 0;  // a non static int that is visible outside of the file

static int myStaticFunc (void)
{
    // a function that is visible only within the file
}

int myNonStaticFunc (void)
{
    // a function that is visible outside the file as well as inside the file
}