对比C语言中extern、static和include头文件

本文围绕C语言中extern与static展开。介绍了static对全局和函数内定义数据的不同含义,对比了extern和include头文件,指出使用include引用所有全局变量和方法有风险,仅用某变量或方法时用extern更好。还通过例子说明用extern声明变量可避免重复定义问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

extern 与 static

修饰符意义
extern变量/函数定义位于其他文件中
<空>变量/函数定义于本文件(公用)且可以用于其他文件
static变量/函数对此文件来说是局部(专用)

static有两重意思。

  • 对于全局定义的数据来说,它意味着”对此文件专用“。
  • 对在一个函数中定义的数据来说,它是指”从静态内存(而不是从临时堆栈)分配的变量。

场景一

main.c

    extern int flag; // 此处仅是声明变量,所以不能初始化
    int main()
    {
        printf("%d", flag);
    }

sub.c

    int flag = 1;

如果在main.cextern int flag = 1,则编译时会出现如下信息:

main.c:5:12: warning: ‘flag’ initialized and declared ‘extern’
 extern int flag=1;
            ^~~~
/tmp/cc7rJpMh.o:(.data+0x0): `flag'被多次定义
/tmp/ccCtPSdg.o:(.data+0x0):第一次在此定义
collect2: error: ld returned 1 exit status

场景二

下面两个文件中的静态变量只在其所在文件中生效,所以不存在冲突

main.c

    static int flag = 4; 
    int main()
    {
        printf("%d", flag);
    }

sub.c

    static int flag = 6;

extern 对比 inlcude头文件

头文件

模块间共享的信息应该放在头文件中。如:

  • 清楚地描述模块做什么,以及能为用户提供什么功能的注释
  • 一般常量
  • 一般结构
  • 所有共用函数原型
  • 公用变量的extern定义

使用extern还是include头文件?

  • 使用include将另一个文件全部包含进去,可以引用另一个文件中所有全局变量和全局方法,存在风险。
  • 如果只是希望使用另一个文件中的某个变量或方法,则使用extern关键字更好。

例子

希望在头文件中定义一个全局变量,然后包含到两个不同的c文件中,希望这个全局变量能在两个文件中共用。测试代码如下:

// main.c
#include <stdio.h>
#include "common.h"
int main()
{
    printf("main.c : %d", key);
    return 0;
}

// common.c
#include "common.h"
void test_f()
{
    printf("common.c : %d", key);
}

// common.h
#ifndef _COMMON_H_
#define _COMMON_H_

int key = 1;

#endif

结果

  1. 编译的时候编译器提示出错,一般提示大概都类似于:Symbol key multiply defined 。也就是说重复定义了key这个变量。这是因为#include命令就是原封不同的把头文件中的内容搬到#include的位置,所以相当于main.c和common.c中都执行了一次int key,而C语言中全局变量是项目内(或者叫工程内)可见的,这样就造成了一个项目中两个变量key,编译器就认为是重复定义。
  2. common.h 中的#ifndef、#define、#endif 的目的避免出现同一个文件中多次包含文件common.h,不能避免重复定义全局变量。

解决办法

使用extern关键字来声明变量为外部变量。在main.c中extern关键字声明变量key为外部变量。

注意:在common.c中由于使用include "common.h",则无需使用extern声明变量key。

总结:变量key在整个工程中只在common.h中被定义一次。

// main.c
#include <stdio.h>

extern int key;
extern void test_f();
int main()
{
    printf("main.c : %d\n", key);
    test_f();
    return 0;
}

// common.c
#include "common.h"

void test_f()
{
    printf("common.c : %d", key);

}

// common.h
#ifndef _COMMON_H_
#define _COMMON_H_

int key = 1;

#endif


参考文献

  1. 《实用C语言编程》2000.05 电力出版社,P356
  2. C语言中extern用法详解
  3. C语言正确使用extern关键字

generated by haroopad

### 3.1 extern关键字的功能 `extern`关键字在C语言中主要用于声明外部变量或函数,其核心功能是告知编译器当前文件中使用的符号(变量或函数)的定义存在于其他源文件中。通过这种方式,可以在多个源文件之间共享变量函数,避免重复定义并提高代码的模块化程度[^5]。 `extern`的一个关键作用是避免重复定义错误。当一个变量或函数需要在多个文件中使用时,只需在一个文件中进行定义,而在其他文件中使用`extern`对其进行声明即可。这样可以确保链接器在最终链接阶段正确解析这些符号,而不会因多次定义而导致错误[^5]。 此外,`extern`允许开发者在当前源文件中声明外部符号,即使它们的确切定义尚未提供。这种机制为程序提供了更大的灵活性,使得开发过程中可以先使用接口,再逐步实现具体功能[^5]。 ### 3.2 extern关键字的使用场景 `extern`关键字最常见的使用场景是在多文件项目中共享全局变量或函数。例如,在一个源文件中定义了一个全局变量,而在另一个源文件中需要访问该变量时,可以通过`extern`来声明它。以下是一个典型的示例: ```c // file1.c int globalVar = 20; // 定义全局变量 ``` ```c // file2.c #include <stdio.h> extern int globalVar; // 声明全局变量 int main() { printf("Global variable value: %d\n", globalVar); // 输出20 return 0; } ``` 在此示例中,`globalVar`在`file1.c`中定义,并在`file2.c`中通过`extern`声明后使用。这体现了`extern`在多文件编程中的重要作用,即实现跨文件的数据共享[^2]。 另一个常见应用场景是声明外部函数。如果某个函数定义在另一个源文件中,但在当前文件中需要调用,则可以直接使用`extern`进行声明。通常,函数默认具有外部链接性,因此`extern`在函数声明中并不总是必需的,但显式使用它可以增强代码可读性一致性[^3]。 ### 3.3 externstatic的区别 `extern`与`static`关键字的作用恰好相反。`extern`用于扩展变量或函数的作用域,使其可以在多个文件中访问;而`static`则用于限制变量或函数的作用域,使其仅在定义它的文件内部可见。这种对比使得开发者可以根据需求选择是否暴露符号的可见性,从而更好地控制模块之间的耦合度[^4]。 ### 3.4 高级应用技巧 除了基本的跨文件变量函数共享外,`extern`还可以用于更高级的场景,如条件编译、动态链接库的导入等。在大型项目中,合理使用`extern`可以显著提升代码的可维护性可扩展性。例如,通过将全局变量集中管理在一个头文件中,并在多个源文件中引用该头文件,可以简化维护流程并减少出错的可能性[^3]。 然而,过度使用`extern`也可能导致代码结构混乱,增加调试难度。因此,在实际开发中应谨慎使用`extern`,并遵循“最小可见性”原则,仅在必要时才将其用于外部符号的声明[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值