https://blog.csdn.net/zjy1175044232/article/details/121354194
https://blog.csdn.net/lqy971966/article/details/89192268
***************************************
-----------------hello.h---------------------
产品名:hello
模块名:hello
日期:2019/4/10
作者:hani
文件描述:hello.c 的头文件
***************************************
#ifndef _HELLO_H_ //防止头文件被重复包含
#define _HELLO_H_
#ifdef __cplusplus // __cplusplus是一个C++规范规定的预定义宏
//如果在c++编译器中编译链接,则执行下列代码,直到最近endif结束
extern "C" { // 表示告诉编译器,这是c写的库文件,请用c约定编译链接,
#endif //因为c++的函数重载会改变编译后的函数名称,而c不支持函数重载
//C++的规则在翻译这个函数名时会把fun这个名字变得面目全非,可能是fun@aBc_int_int#%$也可能是别的
// 变量,数据结构,函数声明等
void printHello();
#ifdef __cpluscplus
}
#endif
#endif //end _HELLO_H_
__cplusplus是一个C++规范规定的预定义宏。你可以信任的是:所有的现代C++编译器都预先定义了它;而所有C语言编译器则不会
所以,如果上述代码被C语言程序引用的话,它的内容就等价于下列代码。
#ifndef _HELLO_H_ //防止头文件被重复包含
#define _HELLO_H_
// 变量,数据结构,函数声明等
void printHello();
#endif //end _HELLO_H_
C语言却是一门单一名字空间的语言,也不允许函数重载,所以,C语言编译器不需要对任何名字进行复杂的处理
C++的缔造者Bjarne Stroustrup在最初就把——能够兼容C,能够复用大量已经存在的C库——列为C++语言的重要目标。
但两种语言的编译器对待名字的处理方式是不一致的,这就给链接过程带来了麻烦。
为了解决这一问题,C++引入了链接规范(linkage specification)的概念,表示法为extern"language string",
C++编译器普遍支持的"language string"有"C"和"C++",分别对应C语言和C++语言。
链接规范的作用是告诉C++编译:对于所有使用了链接规范进行修饰的声明或定义,应该按照指定语言的方式来处理,
比如名字,调用习惯(calling convention)等等。
extern 有两个作用,第一个,当它与"C"一起连用时,如: extern “C” void fun(int a, int b);
则告诉编译器extern “C” {…balabala… }中的这些函数名时按着C的规则去翻译相应的函数名而不是C++的编译规则编译。因为c++的函数重载会改变编译后的函数名称,而c不支持函数重载。
1. 在函数之外定义的变量则称为外部变量,又叫做全局变量;
2. 它的存储方式为静态存储,其生存周期:为整个程序的生存周期。
3. 全局变量可以为本文件中的其他函数所共用,它的有效范围为从定义变量的位置开始到本源文件结束。
其他文件也可见。
因为所有未加static修饰的函数、变量都具有全局可见性,即其他文件可见。
4. 如果全局变量不在文件的开头定义,有效的作用范围将只限于其定义处到文件结束。
5. 如果在定义点之前的函数想引用该全局变量,则应该在引用之前用关键字 extern 对该变量作“外部变量声明”,表示该变量是一个已经定义的外部变量。有了此声明,就可以从“声明”处起,合法地使用该外部变量。
6. 因为全局变量的作用范围是只限于其定义处到文件结束,其他文件也可见,但是其他文件应该怎么使用呢?
那就extern 声明一下即可
参考:
http://c.biancheng.net/view/404.html
通俗易懂说static
https://blog.csdn.net/lqy971966/article/details/88988844
1.对变量而言:
1. 因为全局变量不能在头文件中定义,如果定义会导致各个.c文件包含的这个头文件重复定义;
2. 全局变量可以在.c中定义,只要在.h中声明即可,那么如何声明呢?
加了extern就是声明;
如果没有extern关键字,就是定义;
2.对于函数而言:
有没有extern 是一个意思 都是声明
1. 函数可以再头文件中声明,加与不加extern都是一样的意思。都是声明。
当extern不与"C"在一起,而修饰变量或函数时。extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。
如在头文件中: extern int g_Int; 它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块或其他模块中使用。
extern int g_Int;
如:
test1.c
char a[32];
test1.h
extern char *a;
这样不可以,程序运行时会告诉你非法访问。
原因在于,指向类型char的指针并不等价于类型char的数组。
extern char *a声明的是一个指针变量而不是字符数组,因此与实际的定义不同,从而造成运行时非法访问。
应该将声明改为extern char a[ ]。
下述两个函数声明没有明显的区别:
extern int f();
int f();
main.c
#include
#include"test1.h"
#include"test2.h"
void main(){
fun1();
fun2();
return;
}
test1.h
#ifndef TEST1H
#define TEST1H
//extern char g_str[];
extern char g_str[]="abcde"; // 这个时候相当于没有extern, 等价于 char g_str[]="abcde";
void fun1();
#endif
test1.c
#include
#include "test1.h"
void fun1() {
printf("str=%s\n",g_str);
}
test2.h
#ifndef TEST2H
#define TEST2H
void fun2();
#endif
test2.c
#include
#include "test1.h"
void fun2() {
printf("str=%s\n",g_str);
}
[root@localhost extern-test]# !gcc
gcc main.c test1.c test2.c
/tmp/ccPfBpf2.o:(.data+0x0): multiple definition of `g_str'
/tmp/ccKGoLlw.o:(.data+0x0): first defined here
/tmp/cca1rEcy.o:(.data+0x0): multiple definition of `g_str'
/tmp/ccKGoLlw.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
[root@localhost extern-test]#
multiple definition of `g_str'
因为你把全局变量 g_str 的定义放在了头文件之后,test1.cpp这个模块包含了test1.h所以定义了一次g_str,
而test2.cpp也包含了test1.h所以再一次定义了g_str,这个时候连接器在连接test1和test2时发现两个g_str。
main.c
#include
#include"test1.h"
#include"test2.h"
void main(){
fun1();
fun2();
return;
}
test1.h
#ifndef TEST1H
#define TEST1H
extern char g_str[]; //声明
void fun1();
#endif
test1.c
#include
#include "test1.h"
char g_str[]="abcde"; //定义
void fun1() {
printf("str=%s\n",g_str);
}
test2.h
#ifndef TEST2H
#define TEST2H
void fun2();
#endif
test2.c
#include
#include "test1.h"
void fun2() {
printf("str=%s\n",g_str);
}
[root@localhost extern-test]# !gcc
gcc main.c test1.c test2.c
[root@localhost extern-test]# ./a.out
str=123456
str=123456
[root@localhost extern-test]#
原因:因为把全局变量 数组的定义放在了头文件之后,test1.cpp这个模块包含了test1.h所以定义了一次数组,
而test2.cpp也包含了test1.h所以再一次定义了数组,这个时候连接器在连接test1和test2时发现两个数组。
解决:定义放.c文件中,然后头文件中 extern一下。
a.c 文件中定义了 结构体数组 g_astTESTFileType
b.c 文件要使用它
a.c
/* filetype */
typedef struct tagTEST_FILETYPE
{
CHAR *pcFileName;
CHAR *pcFileDes;
UINT uiFileId;
}TEST_FILETYPE_S;
/* file type */
typedef enum tagTEST_FILETYPE_E
{
TEST_FILETYPE_DOC = 0,
TEST_FILETYPE_PPT,
TEST_FILETYPE_TXT,
TEST_FILETYPE_MAX,
}TEST_FILETYPE_E;
TEST_FILETYPE_S g_astTESTFileType[] =
{
{"DOC", "DOC file type", TEST_FILETYPE_DOC},
{"PPT", "PPT file type", TEST_FILETYPE_PPT},
{"TXT", "TXT file type", TEST_FILETYPE_TXT},
/* add to here */
};
b.c
extern TEST_FILETYPE_S g_astTESTFileType[];
//……使用
g_astWafTPFileType[uiLoop].pcFileName
……
或者在 .h 中 extern TEST_FILETYPE_S g_astTESTFileType[]; 也可以
定义和声明的区别!!!
https://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777431.html