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\n", var, &var);
        return &var;
}

a.c:

#include <stdio.h>

int main(int argc, const char *argv[])
{
        int *ret = NULL;

        ret = func();
        printf("*ret: %d\n", *ret);

        return 0;
}

然后编译运行:

gcc a.c b.c

./a.out
var: 5, &var: 0x55ac51c53010Segmentation 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\n", 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

https://stackoverflow.com/questions/14589314/segmentation-fault-while-accessing-the-return-address-from-a-c-function-in-64-bi

修改如下,在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\n", 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\n", 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\n", 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\n", abc);

        printf("a: %d, b: %d, c:%d\n", abc->a, abc->b, abc->c);

        return 0;
}

运行:

./a.out
abc: 0x55f63c054010
a: 1, b: 2, c:3

原文地址:https://www.cnblogs.com/pengdonglin137/p/9725151.html

时间: 2024-10-01 22:20:50

64位平台上,函数返回指针时遇到的段错误问题的相关文章

在64位平台上的Lucene,应该使用MMapDirectory[转]

http://blog.thetaphi.de/2012/07/use-lucenes-mmapdirectory-on-64bit.html 从3.1版本开始,Lucene和Solr开始在64位的Windows和Solaris系统中默认使用MMapDirectory,从3.3版本开始,64位的Linux系统也启用了这个配置.这个变化使一些Lucene和Solr的用户有些迷茫,因为突然之间他们的系统的某些行为和原来不一样了.在邮件列表中,一些用户发帖询问为什么使用的资源比原来多了很多.也有很多专

程序员之---C语言细节22(函数返回指针注意事项&amp;lt;悬空指针&amp;gt;、查看进程能够分配的内存大小)

主要内容:函数返回指针注意事项<悬空指针>.查看进程能够分配的内存大小 #include <stdio.h> char * favorite_fruit() { static char fruit[] = "apple"; // 不加static的话这个函数还回的指针会悬空,由于在函数退出时fruit组数被销毁 // 加了static后fruit数组分配在数据段里,而不是堆栈中.生命期和程序一样长,函数退出时变量 // 依旧有效 return fruit; }

程序猿之---C语言细节22(函数返回指针注意事项&lt;悬空指针&gt;、查看进程可以分配的内存大小)

主要内容:函数返回指针注意事项<悬空指针>.查看进程可以分配的内存大小 #include <stdio.h> char * favorite_fruit() { static char fruit[] = "apple"; // 不加static的话这个函数还回的指针以及悬空,因为在函数退出时fruit组数被销毁 // 加了static后fruit数组分配在数据段里,而不是堆栈中,生命期和程序一样长,函数退出时变量 // 依然有效 return fruit; }

从函数返回指针

C++ 从函数返回指针 C++ 指针 C++ 指针 在上一章中,我们已经了解了 C++ 中如何从函数返回数组,类似地,C++ 允许您从函数返回指针.为了做到这点,您必须声明一个返回指针的函数,如下所示: int * myFunction() { . . . } 另外,C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量. 现在,让我们来看下面的函数,它会生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们,具体如下: #include <i

C++从函数返回指针

C++ 允许您从函数返回指针.为了做到这点,必须声明一个返回指针的函数,如下所示: int * myFunction() { . . . } 另外,C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量. 现在,来看下面的函数,它会生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们,具体如下: #include <iostream> #include <ctime> using namespace std; // 要生成和返回

对象做函数参数和函数返回值时,调用复制构造函数,构造函数,析构函数的情况

// 对象做函数参数和返回值.cpp : 定义控制台应用程序的入口点.//exit(0)表示正常退出程序,exit(0)表示异常退出 //在调用input时,编译器用对象A去创建了形参对象temp,调用了复制构造函数,对象A中的数据复制给了对象temp// 在input函数中,执行temp.set(s),为对象temp中数据成员str申请了动态储存空间,并设置了输入的字符串//并没有改变实参A中的数据成员str的储存空间,故在执行语句A.show()后输出的字符串并没有改变.在函数调用结束后 /

当您在 64 位 Windows 上运行 Regsvr32.exe 时出现错误信息

尝试运行 Regsvr32.exe 注册在 64 位版本的 Windows 32 位动态链接库 (DLL) 时您会收到以下错误消息: 若要解决此问题,从 %SystemRoot%\Syswow64 文件夹中运行 Regsvr32.exe.请键入以下命令以注册 DLL: cd \windows\syswow64regsvr32 c:\filename.dll

64bit机器 C implicit-function-declaration 函数返回指针 地址值截断问题

昨天碰到了问题,32bit机器正常,但64bit机器crash,把问题简化了下 func_a.h 声明了mystruct * func_a( ); func_a.c定义了 mystruct * func_a( ) { //mystruct * inner进行内存申请和赋值 //print  %p, inner-----address1 0x7ff87804b4a8 return inner; } func_b.c调用了func_a函数(但没有包含func_a的声明) mystruct * pt_

VS2010 win7 64位安装后新建项目生成时错误:LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏

解决方案:VS2010在经历一些更新后,建立Win32 Console Project时会出“error LNK1123” 错误,解决方案为将 项目|项目属性|配置属性|清单工具|输入和输出|嵌入清单 “是”改为“否”即可,但是没新建一个项目都要这样设置一次. 在建立VS2010 Win32 Project项目时,按照上面解决方案依然发生了“error LNK1123”错误,经过上网查资料,解决方案为: 第一步:与上相同. 第二步:将 项目|项目属性|配置属性|连接器|清单文件|嵌入清单 “是”