0

我正在研究一些 C 输出问题,发现以下代码:

http://ideone.com/O0tQnr

在这段代码中,可以看到,在 main 内部,声明了一个具有相同名称的静态变量。为此,我在 Stack-Overflow 上搜索并发现

系统如何识别不同函数中同名的静态变量?

为这个问题给出的答案提出了不同的方法,即。

  1. 静态变量的名称通常包含在调试符号表中。
  2. 一些嵌入式的(编译器)只需在每个重复名称的末尾添加一个数字
  3. 他们很可能在桌子上被破坏了。

我想知道静态变量是如何在 C 中实际实现的,因为所有答案都暗示了一些不同的东西?

另外为了检查这是否只是一次机会,我还运行了代码:

http://ideone.com/zpRVCa

但错误:

prog.c:5:21: error: called object ‘GetSize’ is not a function or function pointer
int myvar=GetSize(GetSize);
                 ^
prog.c:4:11: note: declared here
static GetSize;
       ^

表示编译器发现了一个冲突的声明/重新声明了 Getsize。

4

3 回答 3

2

如果不同的实体具有不同的范围或位于不同的名称空间1中,它们可能具有相同的标识符。在 的情况下int main() { static int main; … },第一个main具有文件范围,第二个main具有块范围。

在任何特定点,在名称空间中只有一个标识符可见。在GetSize(GetSize)中,只有static GetSize是可见的。它隐藏了int GetSize(int),因此该功能GetSize不可见。因此,此代码出错。

在文件范围内声明的标识符static具有内部链接。在块范围内声明的对象标识符没有extern(包括那些有static)没有链接。因为这些标识符没有外部链接,所以它们永远不需要在当前翻译单元之外知道。因此,这些标识符不需要出现在目标文件中:它们的名称不需要对链接器可见。它们通常由编译器在编译翻译单元期间生成的代码访问,并且该代码以数字方式(按内存中的位置)而不是名称来寻址对象。

许多 C 实现提供了调试工具。调试器通常需要知道事物的名称,即使它们有内部链接或没有链接。在这些情况下,C 实现可以使用它希望记录名称信息的任何方案。


1 C的命名空间有:标签名;结构、联合和枚举的标签;结构或联合的成员(每个结构或联合的单独空间);和所有其他标识符。该标准还提到了宏名称的名称空间。

于 2013-08-28T19:05:06.330 回答
2

您描述的两种情况有根本的区别。在第一种情况下:

int main(){
   static main;
   int myvar=GetSize(main);
   printf("%d",myvar);
   return 0;
}

在这里,您在函数内部main并声明了一个静态整数,也称为main. 该函数main是从外部位置调用的,该外部位置知道main作为函数并按原样调用它。在main上面的定义中,你已经重新定义main为静态整数,那么调用GetSize(main)不会导致错误,因为它符合GetSize.

在第二种情况下:

int GetSize(int);
int main(){
   static GetSize;
   int myvar=GetSize(GetSize);
   printf("%d",myvar);
   return 0;
}

在这里,您已将其重新定义GetSize为静态整数,但随后尝试将GetSize其作为函数进行调用。因此,您在定义(静态整数)和如何使用它(函数)方面存在直接冲突。

于 2013-08-28T19:05:24.037 回答
0

错误消息中有一条线索:“不是函数或函数指针”。编译器不能假定 左边的(名称是函数名,因为那里也允许产生函数指针的任何表达式,包括声明为函数指针的变量。

在解析阶段,没有类型检查来帮助找到正确的变量。这是一个由于类似原因而无法运行的程序:

int main(void)
{
  struct { int x,y; } s = {0,0};
  {
    int s;
    printf("%d\n", s.x);
  }
}

外在s能够适应表达s.x,但内在s是可见的。

这是一个有效的程序,因为外部范围的函数不优于内部范围的变量,内部范围的变量恰好是一个能够以自身作为参数调用的函数指针:

#include <stdio.h>
#include <stdlib.h>

void func()
{
  puts("Everything's fine.");
}

void fp()
{
  /* This won't happen. */
  abort();
}

int main(void)
{
  void (*fp)() = func;
  fp(fp);
}
于 2013-08-28T20:01:48.647 回答