64位平臺上,函數返回指針時遇到的段錯誤問題

 

平臺: x86_64spa

GCC:  7.3指針

類型 長度
int 4字節
int * 8字節

 

有以下兩個文件:code

b.c:blog

#include <stdio.h>

static int var = 0x5;

int *func(void)
{
        printf("var: %d, &var: %p\n", var, &var);
        return &var;
}

a.c:ci

#include <stdio.h>

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

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

        return 0;
}

而後編譯運行:get

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\n", ret);

        return 0;
}

運行以下:it

var: 5, &var: 0x56282a30b010
ret: 0x2a30b010

能夠看到,兩者果真不一樣,ret的值僅僅是&var的低4字節的內容。io

通過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

 

 

相關文章
相關標籤/搜索