每个变量在C中都有一个存储类吗?

时间:2019-02-12 20:28:22

标签: c storage-class-specifier

天真地以为有,因为通常不提供存储类关键字时就假定auto

对于文件作用域变量,仍然在其前面加上auto会导致错误。

#include <stdio.h>

auto int x;

int main(void){
  x = 7;
  printf("x = %d", x);
}

C语抱怨:

3:10: error: illegal storage class on file-scoped variable
auto int x;

不使用任何存储类关键字声明x并编译:

#include <stdio.h>

int x;

int main(void){
  x = 7;
  printf("x = %d", x);
}

现在我想知道上面的示例中有什么存储类x?它有名字吗?

3 个答案:

答案 0 :(得分:7)

关键字autostaticexternregister_Thread_local在标准中称为存储类说明符,但是“对象”(这是我们通常称为“变量”的标准术语)没有存储类。相反,它们具有链接(外部,内部,无)和存储持续时间(静态,自动,线程)。另外,对象的任何声明可能是也可能不是定义。存储类说明符以及声明对象的范围以及它是否具有初始化程序(int fooint foo = 3)一起控制这些属性。显示表格如何最简单地显示该信息:

sc-specifier scope initialized   linkage    storage duration    is a definition
------------ ----- -----------   -------    ----------------    ---------------
auto         file  no            [constraint violation]
auto         file  yes           [constraint violation]
auto         block no            none       automatic           yes
auto         block yes           none       automatic           yes

none         file  no            external   static              yes
none         file  yes           external   static              yes
none         block no            none       automatic           yes
none         block yes           none       automatic           yes

static       file  no            internal   static              yes
static       file  yes           internal   static              yes
static       block no            none       static              yes
static       block yes           none       static              yes

extern       file  no            external   static              no
extern       file  yes           external   static              yes
extern       block no            external   static              no
extern       block yes           external   static              yes

“存储类别说明符”一词与“存储持续时间”和“链接”有意不同,以提醒您说明者并不能独立控制存储持续时间和链接。

由于无法使用组合,因此该语言无法让您独立控制存储时间,链接和定义。自动存储持续时间仅对在块作用域中声明的变量有意义,而对于具有外部链接的变量(因为只能在另一个文件中定义),自动定义存储持续时间是有意义的。

我将register_Thread_local遗忘在表之外,因为它们很特殊。 registerauto相似,除了它还表示您不允许使用对象的地址。 _Thread_local使变量的存储持续时间为“线程”,并且不更改链接;它既可以单独使用,也可以与externstatic一起使用,但是将其与“ auto”结合使用是一种约束冲突。我不确定如果您单独在块范围内使用它会做什么。

答案 1 :(得分:4)

根据C标准§6.2.4第3段:

  

其声明的标识符没有存储类说明符_Thread_local且具有外部或内部链接或具有存储类说明符静态的对象具有静态存储持续时间。它的生命周期是程序的整个执行过程,并且在程序启动之前,其存储值仅初始化一次。

强调我的。返回参考第6.2.2节第5段:

  

如果函数的标识符声明没有存储类说明符,则其链接的确定与使用存储类说明符extern声明时完全相同。如果对象的标识符声明具有文件范围并且没有存储类说明符,则其链接是外部的

再次强调我的想法。

因此,默认情况下,全局变量具有静态存储持续时间。即使没有保证的标准,它也是唯一适用于全局变量的存储持续时间类型。

答案 2 :(得分:3)

  

每个变量在C中都有一个存储类吗?

是的,尽管标准实际上为此使用了术语“存储期限”。这是同一回事,而且标准在某些情况下对于关键字autostatic等使用术语“存储类说明符”。

  

天真的人会想到它是有原因的,因为通常在未提供存储类关键字的情况下会假设为自动。

不。绝对不。函数和在文件范围内声明的所有内容的默认值为extern。仅在块范围内声明的对象的标识符默认为auto

  

对于文件作用域变量,仍然在它们前面加上一个auto会导致错误。

应有的。该标准明确规定了

  

存储类说明符autoregister不应出现在外部声明的声明说明符中。

[C11,paragraph 6.9/2]

  

声明x不带任何存储类关键字,它会编译[....]

当然。

  

现在我想知道上面的示例中的x存储类是什么?它有名字吗?

其存储类别是与关键字extern相对应的类别。正如我已经说过的,这是文件作用域声明的默认设置。但是,尽管该标准使用术语“存储类说明符”,但是,它并没有将“存储类”作为独立概念使用。它说话而不是存储 duration 。所有具有外部或内部链接的变量都具有静态存储期限,这意味着它们在程序的整个生命周期中都存在。