http://www.swanlinux.net/2013/05/14/c_extern/
用extern 声明外部变量 定义:外部变量是指在函数或者文件外部定义的全局变量。外部变量定义必须在所有的函数之外,且只能定义一次。 (1) 在一个文件内声明的外部变量 作用域:如果在变量定义之前要使用该变量,则在用之前加 extern 声明变量,作用域扩展到从声明开始,到本文件结束。 例子: #include <stdio.h> int max(int x, int y); // 函数提前声明 int main(int argc, char *argv[]) { int result; extern int X; extern int Y; result = max(X, Y); printf("the max value is %d\n", result); return 0; } int X = 10; //定义外部变量 int Y = 20; int max(int x, int y) { return (x > y ? x : y); } 其中,用 extern 声明外部变量时,类型名可以省略。例如, “extern int X;” , 可以改写成 “extern X;”。 小结: 这种方法简单,实用性不大. (2) 在多个文件中声明外部变量 作用域:如果整个工程有多个文件组成,在一个文件中想引用另外一个文件中已经定义的外部变量时,则只需在引用变量的文件中用extern 关键字加以声明即可。可见,其作用域从一个文件扩展到多个文件了。 例子: 文件 a.c 的内容 #include <stdio.h> int BASE = 2; extern int exe(int x); int main(int argc, char *argv[]) { int a = 10; printf("%d^%d = %d\n", BASE, a, exe(a)); return 0; } 文件 b.c 的内容 #include <stdio.h> extern BASE; // 声明的外部变量 int exe(int x) { int i; int ret = 1; for (i = 0; i < x; i++) { ret *= BASE; } return ret; } 利用gcc 工具编译gcc a.c b.c -o demo, 再运行 ./demo, 结果为 2^10 = 1024 . 其中,在a.c 文件中定义 BASE = 2, 在 b.c 中引用 BASE 时,需要用 extern 关键字声明其为外部变量,否则编译会找不到该变量. 小结:对于多个文件的工程,可以采用这种方法来操作。实际工程中,对于模块化的程序文件,在其文件中可以预先留好外部变量的接口,也就是只采用 extern 声明变量,不定义变量,也通常在模块程序的头文件中声明,
在使用该模块时,只需要在使用时定义一下即可,如上述 b.c 文件,做好相应的函数接口,留好需要改变 BASE 值的声明,在需要使用该模块时,只需要在需要调用的文件中定义具体的值即可。 引用外部变量和通过函数形参值传递变量的区别:用extern 引用外部变量,可以在引用的模块内修改其值,而形参值传递的变量则不能修改其值,除非是地址传递。 因此,如果多个文件同时对需要应用的变量进行同时操作,可能会修改该变量,类似于形参的地址传递,从而影响其他模块的使用,因此要慎重的使用。 (3) 在多个文件中声明外部结构体变量 前一节中,只是适合一般变量的外部声明,但是对于声明外部结构体变量时,则有些不同,需要加以注意。 例子: 文件 a.c 的内容: #include <stdio.h> #include "b.h" #include "c.h" A_class local_post = {1, 2, 3}; A_class next_post = {10, 9, 8}; int main(int argc, char *argv[]) { A_class ret; print("fist point", local_post); print("second point", next_post); ret = fun(local_post, next_post); printf("the vector is (%d %d %d)\n", ret.x, ret.y, ret.z); return 0; } 文件 b.h 的内容: #ifndef __B_H #define __B_H #if 1 typedef struct { int x; int y; int z; } A_class; #endif extern A_class local_post; // 外部结构体变量声明 extern A_class fun(A_class x, A_class y); // 接口函数声明 #endif 文件 b.c 的内容: #include <stdio.h> #include "b.h" A_class fun(A_class first, A_class next) { A_class ret; ret.x = next.x - first.x; ret.y = next.y - first.y; ret.z = next.z - first.z; return ret; } 文件 c.h 的内容: #ifndef __C_H #define __C_H extern int print(char *, A_class post); #endif 文件 c.c 的内容: #include <stdio.h> #include "b.h" int print(char *str, A_class post) { printf("%s:(%d,%d,%d)\n", str, post.x, post.y, post.z); return 0; } 利用 gcc 工具编译 gcc a.c b.c c.c -o demo ,在运行 ./demo ,结果为: [shell] fist point:(1,2,3) second point:(10,9,8) the vector is (9 7 5) 小结: 在 a.c 文件中定义全局变量 A_class local_post 结构体,
并且调用 b.c 中的接口函数 A_class fun(int x, int y) 和 c.c 中的int print(char *str, A_class post),
在b.h 文件中,如果屏蔽掉 A_class 的实现,而在 b.h以外实现,此生将编译出错,由于 c.c 文件中用到 A_class 定义的类型,
所以需要在该文件中包含 b.h。 这里需要说明的是,如果调用外部结构体等多层结构体变量时,需要对这种变量进行实现,使用时,加上模块的头文件即可,否则会报错。 实际工程中,模块化程序文件,一般提供一个 .c 和一个 .h 文件, 其中 .h 文件被 .c 文件调用, .h 文件中实现. 用 extern 声明外部函数 a. 定义函数时,在函数的返回值类型前面加上extern 关键字,表示此函数时外部函数,可供其他文件调用,
如 extern int func(int x, int y), C语言规定,此时 extern 可以省略,隐形为外部函数。 <---> 这一点可以对比static来理解 b. 调用此函数时,需要用extern 对函数做出声明. 作用域: 使用 extern 声明能够在一个文件中调用其他文件的函数,即把被调用函数的作用域扩展到本文件。
C语言中规定,声明时可以省略 extern 例子: 文件 a.c 的内容: #include <stdio.h> #include "b.h" int main(int argc, char *argv[]) { int x = 10, y = 5; printf("x = 10, y = 5\n"); printf("x + y = %d\n", add(x, y)); printf("x - y = %d\n", sub(x, y)); printf("x * y = %d\n", mult(x, y)); printf("x / y = %d\n", div(x, y)); return 0; } 文件 b.h 的内容: #ifndef __F_H #define __F_H extern int add(int, int); extern int sub(int, int); extern int mult(int, int); extern int div(int, int); #endif 文件 b.c 的内容: #include <stdio.h> int add(int x, int y) { return (x + y); } int sub(int x, int y) { return x - y; } int mult(int x, int y) { return x * y; } int div(int x, int y) { if (y != 0) { return (x / y); } printf("mult()fail second para can not be zero!\n"); return -1; } 利用 gcc 工具编译 gcc a.c b.c -o demo ,再运行 ./demo , 结果为: x = 10, y = 5 x + y = 15 x - y = 5 x * y = 50 x / y = 2 小结:由上面简单的例子可以看出,在 b.h 文件中声明好 b.c 的函数,
使用时,只需要在 a.c 中包含 #include “b.h” 头文件即可,这样就可以使用 b.c 的接口函数了,在实际工程中,通常也是采用这种方式, .c 文件中实现函数,.h文件中声明函数接口,需要调用.c文件的函数接口时,只需包含.h文件即可。 总结 在实际工程中,有两种情况比较多。一是利用 extern 只声明外部函数,不需要传递需要外部声明的变量,一个模块化接口文件对应一个声明接口的头文件,需要调用接口函数时,需要包含头文件。二是利用用extern 声明外部函数,同时声明需要传递的外部变量,做法和第一种情况一样,声明都放在头文件中,但是模块文件也需要包含该头文件。另外,如果结构体等比较复杂的变量,则需要包含其定义的头文件。另外,定义的外部变量属于全局变量,其存储方式为静态存储,生存周期为整个的生存周期。
转载于:https://www.cnblogs.com/tureno/articles/6171350.html