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

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

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

<think>嗯,用户问的是C语言中的extern关键字。我需要先回忆一下extern的作用。记得extern主要用于声明变量或函数是在其他文件中定义的,这样多个文件可以共享这些变量或函数。 首先,用户可能是在学习C语言的模块化编程,或者在多文件项目中遇到了链接错误,比如变量未定义或者重复定义的问题。这时候他们可能听说extern可以解决这些问题,所以想了解具体怎么用。 接下来,我应该分几个方面来解释extern的用途。比如,声明外部变量、外部函数,还有可能涉及全局变量的链接性。需要举例子说明在不同文件中如何使用extern来共享变量或函数。 用户可能还不太清楚externstatic的区别,或者为什么有时候不加extern也能访问全局变量,这时候需要解释默认的链接性。同时,可能需要注意extern的作用域链接性,以及在头文件中的正确使用方式,避免重复定义。 另外,用户可能对编译链接的过程不太熟悉,导致他们不理解为什么需要显式声明外部符号。这时候需要简单说明编译单元的概念,以及extern如何帮助链接器找到正确的定义。 还要考虑用户可能的错误使用,比如在多个文件中定义同名的全局变量,导致链接冲突,这时候extern的正确声明可以避免问题。或者误将局部变量声明为extern,导致错误。 最后,应该总结extern的主要用途,并给出一些使用场景的例子,比如全局配置变量、共享函数等。同时,提醒用户注意extern变量的作用域生命周期,以及头文件中使用extern的正确方法,比如配合头文件保护符。 可能还需要提到C++中的extern "C"用法,但用户问的是C语言,所以这部分可能不需要展开,除非用户后续提问。</think>`extern` 是 C 语言中的关键字,用于声明**外部变量或函数**,表示该变量或函数的定义在其他文件中,编译器无需在当前文件中分配存储空间,而是通过链接器在其他编译单元中查找其定义。 --- ### 核心用法与示例 #### 1. **声明外部全局变量** ```c // file1.c int global_var = 10; // 全局变量定义 // file2.c extern int global_var; // 声明外部变量 void print_var() { printf("%d\n", global_var); // 使用其他文件中定义的变量 } ``` #### 2. **声明外部函数** ```c // file1.c void foo() { printf("Hello from foo!\n"); } // file2.c extern void foo(); // 声明外部函数 int main() { foo(); // 调用其他文件中定义的函数 return 0; } ``` #### 3. **全局变量的多文件共享** - **头文件中声明**(如 `global.h`): ```c extern int shared_value; // 声明共享变量 ``` - **源文件中定义**(如 `main.c`): ```c #include "global.h" int shared_value = 42; // 定义并初始化 ``` - **其他源文件使用**(如 `other.c`): ```c #include "global.h" void modify() { shared_value = 100; // 修改外部变量 } ``` --- ### 注意事项 1. **避免重复定义** - 全局变量只能在**一个文件中定义**,其他文件通过 `extern` 声明使用。 - 若多个文件直接定义同名全局变量,链接时会报 `multiple definition` 错误。 2. **默认链接性** - 全局变量函数默认具有 `extern` 链接性(即外部可见),但可通过 `static` 限制作用域。 3. **头文件保护** - 在头文件中使用 `extern` 声明全局变量,避免重复包含导致的重复声明问题。 --- ### 典型错误与解决方案 #### 错误:重复定义 ```c // file1.c int x = 5; // file2.c int x = 10; // 错误:重复定义 x ``` **解决**: - 一个文件保留定义,其他文件改为 `extern int x;`。 #### 错误:未定义 ```c // file1.c extern int y; // 声明 y 在其他文件中定义 int z = y; // 错误:链接时找不到 y 的定义 ``` **解决**: - 确保至少一个文件中定义了 `y`。 --- ### 与其他关键字的区别 | 关键字 | 作用 | 示例 | |----------|--------------------------------|-------------------------------| | `extern` | 声明变量/函数定义在外部文件中 | `extern int count;` | | `static` | 限制变量/函数作用域为当前文件 | `static int helper();` | | `const` | 声明常量(需配合 extern 使用) | `extern const double PI;` | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值