C地址变量范围

时间:2014-11-18 19:24:28

标签: c unix memory

如何打印/查找所有变量(全局,本地,静态等)的地址范围。范围是由任何标准定义的,还是可以使用工具或bash命令获取?感谢您的帮助:))

3 个答案:

答案 0 :(得分:3)

  

如何打印/查找所有变量(全局,本地,静态等)的地址范围。

局部变量通常存储在堆栈中 - 这意味着每次调用函数时它们都有不同的地址,函数调用之间或寄存器中没有地址 - 这意味着它们根本没有地址。

完成链接后,全局变量和静态变量基本相同。它们可能具有固定地址,或者仅在运行时可用的某个段地址的固定偏移量,或者直到运行时才指定的重定位表中的条目。在某些Unix平台上,对象指定默认基地址(或每段基地址),并且只有在与其他地址冲突时才会重新定位(意味着可执行文件通常不会重定位,共享库可能会也可能不会);在其他平台上,无论什么(作为安全功能),一切都总是被重新定位。

此外,变量可能有也可能没有公共符号,具体取决于您编译和链接程序或共享对象的方式。如果是这样,您通常可以使用编译器工具链中的工具查找地址/偏移/重定位条目,例如nmobjtool;如果他们不这样做,那就什么都没有了。

  

范围是否由任何标准

定义

不是任何Unix(或POSIX / SuS)标准。如果你问一个更具体的平台,比如使用标准ABI在x86_64上使用glibc2.3 +的linux,可能会有部分答案,但每个平台的答案都不同。

  

或者我可以使用工具或使用bash命令获取它们

没有内置的bash命令,但是,如上所述,平台和编译器工具链的组合可能有一个工具可以为您提供所需的一些信息。

答案 1 :(得分:1)

变量的起始地址由 address-of 运算符&提供。结束地址可以通过将其大小添加到起始地址减去一个来确定 - 记住在指针算术中向指针添加1会使地址增加对象的大小,因此,最简单的方法是将指针强制转换为{ {1}}因为char*

所以:

sizeof(char) == 1

用于显示此信息的合适宏可能是:

start = &var ;
end = (char*)&var + sizeof(var) - 1 ;

例如以下测试代码:

#define SHOW_ADDRESS_RANGE( var ) printf( #var"\t %p - %p  %u bytes.\n", &var, (char*)&var + sizeof(var) - 1 , sizeof(var) )

输出(例如 - 您的地址可能会有所不同,数据类型大小和结构对齐和打包也可能不同):

#include <stdio.h>

#define SHOW_ADDRESS_RANGE( var ) printf( #var"\t %p - %p  %u bytes.\n", &var, (char*)&var + sizeof(var) - 1 , sizeof(var) )

int a_global_int ;

int main(void) 
{
    static a_static_int ;
    char char_array_10[10] ;
    int int_array_16[16] ;
    int integer ;
    char character ;
    long long long_long ;
    struct
    {
        int x ;
        int y ;
        char array[10] ;
    } a_structure ;

    SHOW_ADDRESS_RANGE( a_global_int ) ;
    SHOW_ADDRESS_RANGE( a_static_int ) ;
    SHOW_ADDRESS_RANGE( char_array_10 ) ;
    SHOW_ADDRESS_RANGE( int_array_16 ) ;
    SHOW_ADDRESS_RANGE( integer ) ;
    SHOW_ADDRESS_RANGE( character ) ;
    SHOW_ADDRESS_RANGE( long_long ) ;
    SHOW_ADDRESS_RANGE( a_structure ) ;

    return 0;
}

根据评论,似乎你可能会问一些不同于我上面回答的问题:

静态数据分配在构建时已知,并且可以由链接器在映射文件中报告。多线程进程每个线程有一个堆栈,并且可以在运行时从堆中分配线程堆栈。链接器地址将是进程加载地址的偏移量,该加载地址由OS加载程序在运行时确定。在现代桌面或服务器操作系统中,地址本身是虚拟的而不是物理的。细节是特定于平台的,Unix的精确细节可能与我所描述的不同。

答案 2 :(得分:0)

链接应用程序时,需要创建链接器映射文件。执行此操作的开关取决于您使用的链接器。这将显示如何分配内存。