可以将本地和寄存器变量声明为extern吗?

Av0*_*v03 10 c extern

我一直想知道extern是否可以在本地声明和寄存器变量.如果它可能会受到什么限制?

chu*_*ica 8

  1. 可以将局部变量声明为extern吗?

不可以extern.但是可以在本地声明全局变量.

// file1.c
int Count;

// file2.c
void foo(void) {
  extern int Count;
  Count++;
}
Run Code Online (Sandbox Code Playgroud)
  1. 注册变量可以声明为extern吗?

不可以.变量可能不是externregister.

C11 dr 6.7.1存储类说明符
1 存储类说明符:
typedef
extern
static
_Thread_local
auto
register
约束
2最多可以在声明中的声明说明符中给出一个存储类说明符,但_Thread_local可能与staticor一起出现的除外extern)


Cir*_*四事件 8

可以将局部变量声明为extern吗?

是的,在某些情况下.

我们来看看C99 N1256标准草案.

该标准将"局部变量"称为具有"块范围".

6.7.1/5存储类说明符说:

具有块作用域的函数的标识符声明不应具有除extern之外的显式存储类说明符.

然后,对于添加extern到局部变量的含义,6.2.2/4标识符的链接说:

对于在该标识符的先前声明可见的范围内使用存储类说明符extern声明的标识符,如果先前声明指定内部或外部链接,则后面声明中的标识符的链接与链接相同在先前的声明中指明.如果没有先前声明可见,或者先前声明未指定链接,则标识符具有外部链接.

让我们打破这些案件.

没有事先声明

void f() {
    extern int i;
}
Run Code Online (Sandbox Code Playgroud)

是相同的:

extern int i;
void f() {}
Run Code Online (Sandbox Code Playgroud)

除了声明只在里面可见f.

这是因为i没有先前的声明可见.i外部链接也是如此(与全局变量相同的链接).

事先声明指定没有链接

void f() {
    int i;
    extern int i;
}
Run Code Online (Sandbox Code Playgroud)

是相同的:

void f() {
    extern int i;
}
Run Code Online (Sandbox Code Playgroud)

因为先前的声明int i没有指定链接,因为第6段说:

以下标识符没有链接:声明为对象或函数以外的任何标识符; 声明为函数参数的标识符; 没有存储类说明符extern声明的对象的块作用域标识符.

事先声明指定内部或外部联系

extern int i;
void f() {
    extern int i;
}
Run Code Online (Sandbox Code Playgroud)

是相同的:

extern int i;
void f() {}
Run Code Online (Sandbox Code Playgroud)

和:

static int i;
void f() {
    extern int i;
}
Run Code Online (Sandbox Code Playgroud)

是相同的:

static int i;
void f() {}
Run Code Online (Sandbox Code Playgroud)

因为在这两种情况下,我们分别有一个先前可见的外部和内部(static)链接声明.

初始化本地外部

无效的C:

void f() {
    extern int i = 0;
}
Run Code Online (Sandbox Code Playgroud)

因为块范围声明具有初始化.

有效C:

extern int i = 0;
void f() {}
Run Code Online (Sandbox Code Playgroud)

但可以说是糟糕的风格,因为相当于较短的:

int i = 0;
void f() {}
Run Code Online (Sandbox Code Playgroud)

因为6.7.8初始化说:

如果标识符的声明具有块作用域,并且标识符具有外部或内部链接,则声明不应具有标识符的初始化程序.

  • Necroposting,但是 - ISO/IEC 9899:1999 6.7.1/p5并没有讨论块范围变量,而是讨论块范围函数.它说`void f(){static void g(){}}`无效,只能为块作用域函数声明指定`extern`. (2认同)
  • 是的,将 `int i` 移到函数之外会将其移动到新的作用域。(每个复合语句都启动一个新块[定义函数的复合语句的块实际上从参数声明的开头开始],选择和迭代语句及其子语句也是如此。)但是,当“int i;”为在任何功能之外,它不具有任何联系;它具有外部链接。对于没有链接后跟不违反约束的外部链接的示例,您可以使用 `void f(void) { int i; { 外部 int 我; ... } }`。 (2认同)

Veg*_*ger 1

您只能将全局变量定义为extern. 告诉编译器(和链接器)它是在其他地方定义的。

局部变量仅存在于局部作用域中,因为它是在堆栈或寄存器中创建的。当执行不在范围内(不再)时,堆栈将展开(因此可用空间再次可用)或寄存器用于其他用途,并且变量(不再)存在。

因此,定义本地外部将是“奇怪的”且不可能的(由于堆栈的使用)。