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

时间:2013-01-15 10:30:18

标签: c extern

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

5 个答案:

答案 0 :(得分:7)

  1. 可以将局部变量声明为extern吗?
  2. 没有。但是可以在本地声明全局变量extern

    // file1.c
    int Count;
    
    // file2.c
    void foo(void) {
      extern int Count;
      Count++;
    }
    
    1. 可以将变量注册为extern吗?
    2. 没有。变量可能不是externregister

        

      C11 dr 6.7.1存储级说明符
        1 存储类说明符:
          typedef
          extern
          static
          _Thread_local
          auto
          register
        约束
        2最多,一个存储类说明符可以在a中的声明说明符中给出   声明,但_Thread_localstatic可能会显示<{1}}

答案 1 :(得分:7)

在某些情况下,局部变量被声明为extern

让我们阅读C99 N1256 standard draft

标准调用&#34;局部变量&#34;具有&#34;阻止范围&#34;。

6.7.1 / 5&#34;存储级说明符&#34;表示:

  

具有块作用域的函数的标识符声明除了extern之外没有明确的存储类说明符。

然后将extern添加到局部变量,6.2.2 / 4&#34;标识符的链接&#34;表示:

  

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

让我们打破这些案件。

没有事先声明

void f() {
    extern int i;
}

与:

相同
extern int i;
void f() {}

除了声明仅在f内可见。

这是因为i没有先前的声明可见。所以i有外部链接(与全局变量相同的链接)。

先前声明指定无链接

void f() {
    int i;
    extern int i;
}

与:

相同
void f() {
    extern int i;
}

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

  

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

先前声明指定内部或外部链接

extern int i;
void f() {
    extern int i;
}

与:

相同
extern int i;
void f() {}

static int i;
void f() {
    extern int i;
}

与:

相同
static int i;
void f() {}

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

初始化本地外部

无效的C:

void f() {
    extern int i = 0;
}

因为块范围声明有初始化。

有效C:

extern int i = 0;
void f() {}

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

int i = 0;
void f() {}

因为6.7.8初始化说:

  

如果标识符的声明具有块范围,并且标识符具有外部或内部链接,则声明不应具有标识符的初始化器。

答案 2 :(得分:3)

6.9 C99的外部定义指出:

  

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

答案 3 :(得分:1)

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

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

因此定义一个本地extern将是“奇怪的”和不可能的(由于堆栈的使用)。

答案 4 :(得分:0)

短语register variable对我来说并不清楚,因此我会粗略猜测OP真正感兴趣的内容,并将原始问题改为:Could local variables be declared with extern specifier?,如下所示:

int main() {
    extern int x; // Is this OK?
    return 0;
}

答案是肯定的。

范围(可见性)和存储是两个独立且相互关联的概念。这里,x是一个局部变量(范围),它只在此块中可见。 extern指示存储,这意味着这只是一个声明,此变量在其他地方定义。建议C标准明确参考。

对于省略的register部分,我假设OP意味着一个带有register存储类说明符的变量,如register int x。然后,同时指定registerextern是非法的。

int main() {
    extern auto int x; // This is wrong.
    return 0;
}

At most, one storage-class specifier may be given in the declaration specifiers in a declaration, except that _Thread_local may appear with static or extern.

对称问题是:用全局或外部变量指定autoregister是否有效,这正是Alexey Frunze的回答。

auto int x; // This is wrong.
int main() {
    return 0;
}