C 语言中的 extern 关键字

Jinku Hu 2021年2月7日
C 语言中的 extern 关键字

本文将演示关于如何在 C 语言中使用 extern 关键字的多种方法。

C 语言中使用 extern 关键字来声明一个在其他文件中定义的变量

一般来说,C 语言的变量有 3 种不同的链接类型:外部链接、内部链接或无链接。如果一个变量定义在块或函数范围内,就认为它没有链接。一个具有文件作用域的变量可以有内部链接或外部链接。也就是说,如果一个全局变量用 static 限定符声明,它就具有内部链接,意味着该变量可以在一个源文件(更准确的说是翻译单元)中使用。没有 static 限定符的全局变量被认为具有外部链接,可以在不同的源文件中使用。如果要使用在其他源文件中定义的全局变量,应该使用关键字 extern 来声明。

#include <stdio.h>
#include <stdlib.h>

#ifndef COUNT
#define COUNT 10
#endif

extern int counter;

int main(void) {

    printf("counter: ");
    for (int i = 0; i < COUNT; ++i) {
        counter += 1;
        printf("%d, ", counter);
    }
    printf("\b\b \n");

    exit(EXIT_SUCCESS);
}

输出:

counter: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

extern 限定变量通常定义在不同文件的某个地方。不过,从技术上讲,我们还是可以在同一个文件中使用 extern 关键字来声明全局变量,如下例所示。这种类型的声明本质上是多余的,因为编译器会自动使变量名在同一文件范围内的任何地方可见。

#include <stdio.h>
#include <stdlib.h>

#ifndef COUNT
#define COUNT 10
#endif

int counter2 = 0;

int main(void) {

    extern int counter2; //redundant
    counter2 += 10;
    printf("%d\n", counter2);

    exit(EXIT_SUCCESS);
}

不过要注意,extern 声明的变量不应该被初始化,因为如果我们在一个源文件中定义 const char*全局变量,然后用一些字符串文字值初始化它,会导致编译器警告。在不同的源文件中声明同一个没有 const 修饰符的变量,在编译时不会出现警告,而且会删除对象的 const 性。因此,如果用户试图修改只读字符串 tmp,编译器不会抛出错误,但程序会遇到分段故障。

#include <stdio.h>
#include <stdlib.h>

#ifndef COUNT
#define COUNT 10
#endif

extern int counter;
//extern int counter = 3; // erroreous
extern char *tmp; // erroreous

int counter2 = 0;

int main(void) {

    printf("counter: ");
    for (int i = 0; i < COUNT; ++i) {
        counter += 1;
        printf("%d, ", counter);
    }
    printf("\b\b \n");

    tmp[0] = 'S'; // segmentation fault
    printf("%s", tmp);

    exit(EXIT_SUCCESS);
}
Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn