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

问题描述 投票:3回答:3

天真的人可能会认为它有,因为通常在没有提供存储类关键字时会使用auto

但是,对于文件范围的变量,将auto放在它们前面会产生错误。

#include <stdio.h>

auto int x;

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

Clang抱怨说:

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的存储类是什么?它有名字吗?

c storage-class-specifier
3个回答
7
投票

关键字autostaticexternregister_Thread_local在标准中称为存储类说明符,但“对象”(这是我们通常称之为“变量”的标准术语)没有存储类。相反,它们具有链接(外部,内部,无)和存储持续时间(静态,自动,线程)。此外,对象的任何声明可能是也可能不是定义。存储类说明符以及声明对象的范围以及它是否具有初始值设定项(int foo vs int 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排除在桌面之外,因为它们很特别。 register就像auto一样,但它也意味着你不能获取对象的地址。 _Thread_local使变量的存储持续时间为“线程”,并且不会改变链接;它可以单独使用或与externstatic一起使用,但将它与“auto”结合起来是违反约束的。如果你在块范围内单独使用它,我不确定它会做什么。


4
投票

从C标准§6.2.4第3段:

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

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

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

再次强调我的意思。

因此,全局变量默认具有静态存储持续时间。即使没有标准来保证,它也是唯一一种对全局变量有意义的存储持续时间。


3
投票

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

是的,虽然标准实际上使用了术语“存储持续时间”。它是相同的,并且标准有点不一致使用术语“存储类说明符”关键字autostatic等。

天真的人可以认为它有,因为通常在没有提供存储类关键字时自动。

不,绝对不是。对于函数和在文件范围内声明的任何内容,缺省值为extern。只有在块范围内声明的对象的标识符才会默认为auto

但是,对于文件范围的变量,将auto放在它们前面会产生错误。

正如它应该。该标准明确指明了这一点

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

[C11,paragraph 6.9/2]

声明x没有任何存储类关键字,它编译[....]

当然。

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

它的存储类是对应关键字extern。正如我已经说过的,这是文件范围声明的默认值。但是,尽管该标准使用术语“存储类说明符”,但它并未将“存储类”用作独立概念。它说话而不是存储持续时间。具有外部或内部链接的所有变量都具有静态存储持续时间,这意味着它们存在于程序的整个生命周期中。

© www.soinside.com 2019 - 2024. All rights reserved.