64位平台上,函数返回指针时遇到的段错误问题
Posted pengdonglin137
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了64位平台上,函数返回指针时遇到的段错误问题相关的知识,希望对你有一定的参考价值。
平台: x86_64
GCC: 7.3
类型 | 长度 |
int | 4字节 |
int * | 8字节 |
有如下两个文件:
b.c:
#include <stdio.h> static int var = 0x5; int *func(void) { printf("var: %d, &var: %p ", var, &var); return &var; }
a.c:
#include <stdio.h> int main(int argc, const char *argv[]) { int *ret = NULL; ret = func(); printf("*ret: %d ", *ret); return 0; }
然后编译运行:
gcc a.c b.c ./a.out var: 5, &var: 0x55ac51c53010
Segmentation fault (core dumped)
可以看到,在访问返回的地址时发生了段错误,第一感觉不应该啊,b.c里定义的是static变量,并不是局部变量啊。那么我们把返回的指针具体数值打印出来,看跟b.c中打印的是否一致,修改a.c如下:
#include <stdio.h> int main(int argc, const char *argv[]) { int *ret = NULL; ret = func(); printf("ret: %p ", ret); return 0; }
运行如下:
var: 5, &var: 0x56282a30b010 ret: 0x2a30b010
可以看到,二者果然不同,ret的值仅仅是&var的低4字节的内容。
经过Google,发现,原来是没有在a.c中对func()进行声明,如果没有对func声明,GCC会默认认为func返回的是int类型,而x86_64上,指针占用8个字节,int类型仅仅占用4个字节,所以在赋值时只会把&val的低4字节赋值给ret。
可以参考:
https://stackoverflow.com/questions/23144151/64-bit-function-returns-32-bit-pointer
修改如下,在a.c中增加对func的声明,告诉编译器func的返回值是一个指针类型,需要占用8个字节长度
#include <stdio.h> extern int *func(void); int main(int argc, const char *argv[]) { int *ret = NULL; ret = func(); printf("ret: %p, *ret: %d ", ret, *ret); return 0; }
输出:
var: 5, &var: 0x561cb45bd010 ret: 0x561cb45bd010, *ret: 5
与此类似的还有一种:
.
├── a.c
├── b.c
├── common.h
common.h:
#ifndef __ABC_H__ #define __ABC_H__ struct ABC { int a; int b; int c; }; #endif
b.c:
#include "common.h" static struct ABC abc = { 1, 2, 3 }; struct ABC *func(void) { return &abc; }
a.c:
#include <stdio.h> extern struct ABC *func(void); int main(int argc, const char *argv[]) { int *ret = NULL; struct ABC *abc = func(); printf("abc: %p ", abc); return 0; }
编译运行:
gcc a.c b.c ./a.out abc: 0x55ed86710010
没有问题,但是如果在a.c中去访问结构体成员的话,编译就会失败:
gcc a.c b.c a.c: In function ‘main’: a.c:12:36: error: dereferencing pointer to incomplete type ‘struct ABC’ printf("a: %d, b: %d, c:%d ", abc->a, abc->b, abc->c);
原因是,在x86_64上,不管是什么类型的指针,GCC都会会分配8个字节,这个不会有问题,但是如果要访问指针指向的结构体成员的话,就需要告诉GCC这个成员具体是什么样子。解决办法同时是需要声明一下结构体类型,这里包含对应的头文件即可。
#include <stdio.h> #include "common.h" extern struct ABC *func(void); int main(int argc, const char *argv[]) { int *ret = NULL; struct ABC *abc = func(); printf("abc: %p ", abc); printf("a: %d, b: %d, c:%d ", abc->a, abc->b, abc->c); return 0; }
运行:
./a.out abc: 0x55f63c054010 a: 1, b: 2, c:3
完
以上是关于64位平台上,函数返回指针时遇到的段错误问题的主要内容,如果未能解决你的问题,请参考以下文章