C 地址变量的范围



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

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

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

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

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

是否由任何标准定义的范围

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

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

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

变量

的起始地址由运算符 & 提供。结束地址可以通过将其大小与起始地址相加 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;
}

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

a_global_int     0x8049948 - 0x804994b  4 bytes.
a_static_int     0x8049944 - 0x8049947  4 bytes.
char_array_10    0xbf856502 - 0xbf85650b  10 bytes.
int_array_16     0xbf856520 - 0xbf85655f  64 bytes.
integer  0xbf8564f4 - 0xbf8564f7  4 bytes.
character    0xbf8564f3 - 0xbf8564f3  1 bytes.
long_long    0xbf8564f8 - 0xbf8564ff  8 bytes.
a_structure  0xbf85650c - 0xbf85651f  20 bytes.

根据评论,您似乎在问与我上面回答的不同的问题:

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

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

最新更新