【问题标题】:Storage class declarations存储类声明
【发布时间】:2012-05-04 19:30:34
【问题描述】:

以下声明正确吗?

在任何函数之外:

int a; //external by default
extern int a; //explicitly extern
static int a; //explicity static
const int a; //static by default
static const int a; //explicitly static
extern const int a; //explicitly extern

函数内部:

int a; //auto by default
static in a; //explicity static
const int a; //static by default
static const int a; //explicitly static

【问题讨论】:

  • const 对存储持续时间或链接没有影响,即相同的规则适用于const 和非const 变量...
  • 另请参阅port70.net/~nsz/c/c99/n1256.html#6.9.2 关于文件范围定义的示例...

标签: c variables static declaration extern


【解决方案1】:

关闭。

默认情况下,全局范围内的任何内容(即:函数外)都是静态的。

例如:

//main.c
int myVar;  // global, and static

int main(void) {
  ...
  return 0;
}

//morecode.c
extern int myVar; //other C files can see and use this global/static variable

但是,如果您在全局范围内将某些内容显式声明为静态,则它不仅是静态的,而且仅在该文件中可见。其他文件看不到。

//main.c
static int myVar;  // global, and static

int main(void) {
  ...
  return 0;
}

//morecode.c
extern int myVar; // compiler error; "myVar" can only be seen by 
                  // code in main.c since it was explicitly 
                  // declared static at the global scope

此外,默认情况下没有什么是“外部”。您通常使用 extern 从其他文件访问全局变量,前提是它们没有像上面的示例中那样显式声明为静态。

const 仅表示数据不能更改,无论其范围如何。它并不意味着外部或静态。有些东西可以是“extern const”或“extern”,但“extern static”并没有真正意义。

作为最后一个示例,此代码将构建在大多数编译器上,但它有一个问题:myVar 总是被声明为“extern”,即使在技术上创建它的文件中也是如此。不好的做法:

//main.c
extern int myVar;  // global, and static, but redundant, and might not work
                   // on some compilers; don't do this; at least one .C file
                   // should contain the line "int myVar" if you want it 
                   // accessible by other files
int main(void) {
  ...
  return 0;
}

//morecode.c
extern int myVar; //other C files can see and use this global/static variable

最后,如果您还不熟悉这篇文章,您可能希望涵盖各个级别的范围。它可能对您有所帮助和信息丰富。祝你好运!

Terminology definition - Scope in C application

在我看来,回答我这个关于范围问题的人做得很好。

另外,如果你在函数中声明了一些静态的东西,那么值会在函数调用之间保持不变。

例如:

int myFunc(int input) {
  static int statInt = 5;
  printf("Input:%d  statInt:%d",input,statInt);
  statInt++;
  return statInt;
}

int main(void) {
  myFunc(1);
  myFunc(5);
  myFunc(100);
  return 0;
}

输出:

Input:1  statInt:0
Input:5  statInt:1
Input:100  statInt:2

请注意,在函数中使用静态变量的情况有限且数量有限,因此对于大多数项目来说通常不是一个好主意。

【讨论】:

  • static const int i; 是一个有效的声明吗?
  • 是的。如果您在全局范围内执行此操作,则您创建了一个只能在该文件中访问的 const 变量。此外,该值只能在定义时设置,因此使用有意义的唯一方法是: static const int ConsCanOnlyBeSeenInThisFile = 1;例如。如果你在一个函数中这样做,它会产生类似的效果,但只能在函数范围内看到。请记住,如果您将函数中的变量设置为静态,则其值在调用之间保持不变。
【解决方案2】:

您的一个误解似乎是externstatic 相反。不是这种情况。你有这个:

int a; //extern by default

这不是“默认外部”。 extern 声明意味着实际的变量定义在别处。所以如果你的源文件中有这个:

extern int a;

然后在其他地方你有另一个源文件:

int a;

否则,如果你编译你的代码,你会得到:

/tmp/cc3NMJxZ.o: In function `main':
foo.c:(.text+0x11): undefined reference to `a'
collect2: ld returned 1 exit status

static 在函数定义之外意味着该变量仅对同一文件中定义的其他代码可见。缺少static 意味着该变量对于可能链接到您的目标文件的代码是全局可见的。

我不太确定,但我不相信const 暗示static。这应该不会太难测试。

...事实上,一个非常简单的测试证实const 并不暗示static

【讨论】:

  • extern 并不一定意味着该定义在另一个文件中。 extern 声明和定义都可以在同一个文件中。 extern 只是表示`这个变量的定义存在于某处(可以在任何地方)
  • extern by default 是正确的,因为文件范围变量默认具有外部链接;然而,链接和说明符 externstatic 之间的联系并不像人们想象的那么简单......
  • @Christoph,我不确定我是否明白你在说什么。 extern int aint a 之间有很大的区别,除非我很困惑,它认为 int a 不能称为“默认情况下的外部”。
  • int a; 在文件范围内是一个带有外部链接的暂定定义,int a = 42;extern int a = 42; 都是等效的外部定义,extern int a; 是一个声明(不是定义)如果它是翻译单元中的第一个声明,则具有外部链接 - 否则,它引用前一个声明;有点乱,真的……
  • @larsks 这是一个错字。我的意思是“外部”而不是“外部”。
【解决方案3】:

您必须将存储持续时间和链接的概念分开。 externstatic 在各种情况下都可能对这些属性和其他效果产生影响,但不是其中任何一个的唯一决定因素。

在文件范围内


int a;

这是一个暂定定义。 a 具有静态存储时长和外部链接。


extern int a;

声明而不是定义。静态存储持续时间和外部链接(或由先前声明确定的链接,如果一个可见)。


static int a;

暂定定义。静态存储时长和内部链接。


const int a;

暂定声明。静态存储持续时间和外部链接(与 C++ 不同)。


static const int a;

暂定定义。静态存储时长和内部链接。


extern const int a;

声明而不是定义。静态存储持续时间和外部链接(或由先前声明确定的链接,如果一个可见)。


在块范围内


int a;

定义。自动存储时长,无联动。


static int a;

定义。静态存储时长,无关联。


const int a;

定义。自动存储期限,无联动。 (我认为这是严格合法的,但不是很有用,因为你不能修改 a 的不确定初始值而不导致未定义的行为。)


static const int a;

定义。静态存储时长,无联动。 (同样,不是很有用!)

【讨论】:

  • 小修正:extern int a; 在文件范围内只有在没有先前声明具有内部链接的情况下才具有外部链接;问题和答案中也缺少:块范围外部声明
  • @Christoph:没错,我假设这些是它们各自范围内的第一个(或唯一一个)声明。
  • 另外,我不会说块范围的static const int a; 没有用 - 具有静态存储持续时间的对象被隐式零初始化,因此该值是明确定义的;我经常使用这些变量,例如初始化分配的对象
  • @Christoph:很公平,虽然int 版本没有 有用,你不妨使用0(除非你有一个非常好的名字在某些领域具有特殊含义的零)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多