一般情况下如果我们想使用其他文件的函数时,常规操作是将该函数在头文件中声明,然后在需要使用的文件里引用这个头文件
但若是没声明呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
11.c
#include <stdio.h>
extern char* b;
int main() {
printf("aaa--d:%x----%s--p\n", aaa(),b,b);
char*p = aaa();
printf("p = %p\n", p);
if(p)
printf("---\n");
printf("value = %s\n",p);// 崩溃!
return 0;
}
2.c
char *b="aaa";
char* aaa(){ return b;}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
gcc 11.c 2.c -o test
11.c: In function ‘main'
11.c:4:37: warning:: implicit declaration of function ‘aaa'[-Wimplicit-function-declaration]
4| printf("aaa--d:%x----%s--%p\n",aaa(),b,b);
| ^~~
11.c:5:15: warning:: initialization of ‘char *’ fromn‘int' makes pointer from integer without a cast [-Wint-conversion]
5| char *p = aaa();
| ^~~
./test
aaa--d:4b1c032----aaaa--0x560604b1c032
p=0x4b1c032
---
Segmentation fault (core dumped)
|
这里并没有引用这个头文件,为什么依然可以使用呢?
这就引出了一个概念:隐式声明。
简单来讲就是当前文件使用没有声明的函数时,编译器会自动声明一个,但返回值是int类型
那为什么会出现段错误呢?
上面编译运行的环境是64bit的:
char* aaa() 返回的是一个指针8B(64bit) 但是在编译时 已经确定了是返回值类型(由于是隐式声名,编译器默认是int) 是int 4B(32bit) ,所以就会把指针的低32bit 取出来 赋给char* *p 指针p 的值就是一个截断的值, 这个指针就变成了一个非法的了,如果取访问其指向的内存,就会出现 段错误.
如果是32bit 环境呢
int 是4B 指针也是4B ,指针不会被截断,还是原来的值,不会出现非法访问.
如何避免呢: 在Makefile 里加上 -Wall -Werror ,编译时会检测出这种错误