> ## Content Index
> Fetch the complete content index at: https://blog.hacking.pub/llms.txt
> Use this file to discover other available public pages before exploring further.

# extern c
- URL: https://blog.hacking.pub/2017/04/16/extern-c/
- Published: 2017-04-16T12:03:21.000Z
- Updated: 2017-04-16T12:03:21.000Z
- Author: chainhelen
- Tags: c语言, extern, 编译原理, 汇编

#### 函数签名

**Function Signature**，函数签名包含了一个函数的信息，包括函数名、它的参数类型、它所在的类和名称空间及其他信息。  
编译过程中，编译器（或者链接器）处理符号时，他们使用某种名称修饰的方法，使得每个函数签名对应一个修饰后名称（Decorated Name）。  
（内容主要摘抄《程序员的自我修养》）

以下表格是c++代码编译过后在gcc编译器下的符号名

| 函数签名                 | 修饰后名称（符号名）       |
| -------------------- | ---------------- |
| int func(float)      | \_Z4funcf        |
| float func(float)    | \_Z4funcf        |
| int C::func(int)     | \_ZN1C4funcEi    |
| int C::C2::func(int) | \_ZN1C2C24funcEi |
| int N::func(int)     | \_ZN1N4funcEi    |
| int N::C::func(int)  | \_ZN1N1C4funcEi  |

而gcc编译器编译纯c代码，修饰后名称跟原函数签名相同 

#### extern

extern的问题在于不知道关键词出现的时候到底是声明还是定义。  
`声明可以多次，定义只能一次`

要点:

1. 函数的声明extern关键词是可有可无的，因为函数本身不加修饰的话就是extern的。但是引用的时候一样是需要声明的
2. 而全局变量在外部使用声明时，extern关键词是必须的，如果变量无extern修饰且没有显式的初始化，同样成为变量的定义，因此此时必须加extern，而编译器在此标记存储空间在执行时加载如内存并初始化为0
3. 而局部变量的声明不能有extern的修饰，且局部变量在运行时才在堆栈部分分配内存

分类:

（1）变量

```js
extern int a;  // 声明一个全局变量a
int a;         // 定义了一个全局变量
extern int a = 0; //定义个全局变量a，赋值初始化
int a = 0;  //定义一个全局变量a，赋值初始化

```

（2）函数

```js
// 定义了一个全局函数
int func(void)
{
    return 0;
}

//声明了一个全局函数
int fun(void);

//函数声明，所以省略了extern，完整些是extern int fun(void);

```

对变量而言，如果你想在本源文件中使用另一个源文件的变量，就需要在使用前用extern声明该变量，或者在头文件中用extern声明该变量。 

对函数而言，如果你想在本源文件中使用另一个源文件的函数，就需要在使用前用声明该变量，声明函数加不加extern都没关系，所以在头文件中函数可以不用加extern。 

#### 规则

```
规则1　头文件(.h)中是对于该模块接口的声明，接口包括该模块提供给其它模块调用的外部函数及外部全局变量，对这些变量和函数都需在.h中文件中冠以extern关键字声明；  

规则2 模块内的函数和全局变量需在.c文件开头冠以static关键字声明；  

规则3 永远不要在.h文件中定义变量；  

规则4 如果要用其它模块定义的变量和函数，直接包含其头文件即可。  

```

#### 实践

`g++ -E main.cpp -o main.i -v`  
`g++ -c main.cpp -o main.o -v`

//查看  
`cat main.i`  
`readelf -s mian.o`

```
// 例子1
#include <stdlib.h>

int main() {
    char *p = (char *)malloc(4);
    free(p);
    return 0;
}

```

可以在main.i看见 extern void \*malloc (size\_t \_\_size)  
是被包裹在extern c里面，也就是说这个malloc的函数签名按照gcc的符号修改修饰  
再来看看main.o关于malloc的符号表，在符号表里面可见"malloc"，所以程序能正常链接到标准c语言库的malloc

```
Symbol table '.symtab' contains 11 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS main.cpp
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     8: 0000000000000000    41 FUNC    GLOBAL DEFAULT    1 main
     9: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND malloc
    10: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND free

```

```
// 例子2
#include <stdlib.h>

extern void *malloc(int);

int main() {
    char *p = (char *)malloc(4);
    free(p);
    return 0;
}

```

```
Symbol table '.symtab' contains 11 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS main.cpp
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     8: 0000000000000000    41 FUNC    GLOBAL DEFAULT    1 main
     9: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _Z6malloci
    10: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND free

```

按照g++的符号修饰

---

#### 参考

[extern使用方法总结](http://www.cnblogs.com/ziwuge/archive/2011/12/21/2295325.html?ref=blog.hacking.pub)  
[extern 用法，全局变量与头文件（重复定义）](http://www.cnblogs.com/chengmin/archive/2011/09/26/2192008.html?ref=blog.hacking.pub)