即使在函数调用完成后,也可以访问堆栈上的内存位置

hag*_*wal 1 c stack

我有以下程序:

#include <stdio.h>
#include <stdlib.h>

int* testPointerReturnType();

int main(void)
{
    int x = 2;
    printf("Value of x is %d and its address is %p\n", x, &x);
    int* y = testPointerReturnType();
    printf("Value of y is %d and its address is %p\n", *y, y);    
}

int* testPointerReturnType()
{
    int x = 33;
    int r = 99;
    return &x;
}
Run Code Online (Sandbox Code Playgroud)

以下是我的整体o/p(我将在下面的问题中讨论这个问题):

// This is with ** int r = 99; ** line commented
jharvard@appliance (~/psets/pset5/pset5_test): ./PointerAddresss 
Value of x is 2 and its address is 0xbfdba7c4
Value of y is 33 and its address is 0xbfdba794
jharvard@appliance (~/psets/pset5/pset5_test): size PointerAddresss
   text    data     bss     dec     hex filename
   1250     280       4    1534     5fe PointerAddresss


// This is with ** int r = 99; ** line un-commented
jharvard@appliance (~/psets/pset5/pset5_test): ./PointerAddresss 
Value of x is 2 and its address is 0xbf8a98e4
Value of y is 33 and its address is 0xbf8a98b4
jharvard@appliance (~/psets/pset5/pset5_test): size PointerAddresss
   text    data     bss     dec     hex filename
   1266     280       4    1550     60e PointerAddresss
jharvard@appliance (~/psets/pset5/pset5_test): 
Run Code Online (Sandbox Code Playgroud)

以下是我的问题:

  1. 我正在返回局部变量的内存地址,但是在该函数完成执行后我仍然能够访问该位置.怎么样?是否有可能内存位置仍然保留该值并且尚未被覆盖.这意味着如果我的程序只调用了一个函数并且该函数返回了一个内存地址,那么我仍然可以访问本地变量的内存地址并获得相同的值,因为没有调用其他函数?
  2. 如果我保留int r = 99;评论然后我进入1250文本和dec.如果我取消注释然后我得到1266,这基本上意味着增加16个内存位置,但是当为什么增加16个内存位置时4个字节的int?另外,我知道文本/代码段然后是什么dec

Dav*_*zer 7

当然,除非堆栈的大小再次增加到足以覆盖该值,否则内存位置仍然可以保留该值,但是您正在基于未定义的行为进行操作.这可能意味着没有调用其他函数,但它也可能意味着没有其他函数需要在堆栈上分配那么多空间才能运行.

您看到分配的内存超出预期的原因是堆栈对齐.如果您阅读了适用于您的平台的应用程序二进制接口文档,您会发现这个描述很好

我没有提到这一点,但是如果你在函数中标记局部变量static,你仍然会做很糟糕的事情,但是你可以通过指针在函数调用结束后可靠地继续访问该值,因为该值将不再被分配在堆栈上.

最后,我刚看到你的最后一个问题. dec小数.如果您将0x60e转换为十进制,您将获得1550.


大卫有关堆栈对齐的更多信息,从他的评论中得出答案 - hagrawal.

堆栈对齐对于访问元素的速度和调用的一致性是必需的.这样,事物最好在内存中对齐以便快速访问,并且被调用的函数不必"想知道"事情的位置.这意味着分配一个字节通常会导致在堆栈上分配2,4,8,16甚至更多字节,这些都取决于对齐要求.

  • 这个陈述可能是故事的一部分_Stack对齐对于元素的访问速度和调用的一致性是必需的.通常,这些指令要求使用未对齐数据.现在,x86-64的许多库都是使用SIMD指令生成的,这些指令仅适用于对齐的数据.因此,如果您的值没有正确对齐(包括堆栈),您最终可能会出现seg错误.在PPC上,您可能会因错误对齐而导致总线错误. (2认同)