[Linux] linux中C程序运行时的数据分布

在用C语言编程时,一直有个疑惑:

char *a = "abc";

char b[4] = "abc";

这两句在C语言中有什么不同吗?

按理来说,a和b都是局部变量,只不过一个是指针,一个是数组。有人说,两个的长度不一样,从C风格的字符串来说是的,第一个长度为3,第二个的长度为4,其实也可以将第二个的长度改为3,只不过打印时就不太好看了。

其实,更深层次的问题是,当程序运行时,对于这两行代码,"abc"出现在哪儿?


1 常量字符串去哪儿了

运行下面一个简单的程序:

#include 

int main()
{
    char *a = "abc";
    char b[4] = "abc";

    printf("char*  address : %p\t a address : %p\n", a, &a);
    printf("array  address : %p\t b address : %p\n", b, &b);

    while(1) ;

    return 0;
}

上面的代码分别定义了一个char*变量和一个char型数组,然后分别打印它们的地址。

最后一个while循环是为了不让程序结束,以便查看程序运行时的数据存放的位置。

将以上代码编译运行后:

[Linux] linux中C程序运行时的数据分布_第1张图片

程序已经打印出了两个字符串的地址以及a和b的地址,然后在一个新的terminal中执行下面的命令:

[Linux] linux中C程序运行时的数据分布_第2张图片

首先输入ps -aux | grep a.out在查看a.out的进程ID,然后用cat命令查看该进程的各个段的地址。

08048000-08049000 r-xp  代码段
08049000-0804a000 r--p  没看到有这个地址的数据
0804a000-0804b000 rw-p  数据段

bff35000-bff56000 rw-p 栈

由于程序中没有进行动态内存分配,因此没有显示堆。

将上面的地址与程序运行打印的结果进行对比:

对于char *a = "abc","abc"与代码段存放在一起,在栈中分配了一个指针,它的值就是"abc"的地址。

对于char b[4] = "abc","abc"存放在栈中,变量b的值等于"abc"在栈中的地址,可以假想成b是一个符号,它对应"abc"的首地址。


2 linux中C程序运行时数据的分布

用上面类似的方法处理下面的程序:

#include 

int g_init = 1;
int g_uinit;
static int s_g_init = 1;
static int s_g_uinit;
const int c_g = 1;

int main()
{
    int l_init = 1;
    int l_uinit;
    static int s_l_init = 1;
    static int s_l_uinit;
    const int c_l = 1;

    printf("         global init : %p\n", &g_init);
    printf("       global uninit : %p\n", &g_uinit);
    printf("  static global init : %p\n", &s_g_init);
    printf("static global uninit : %p\n", &s_g_uinit);
    printf("        const global : %p\n\n", &c_g);

    printf("          local init : %p\n", &l_init);
    printf("        local uninit : %p\n", &l_uinit);
    printf("   static local init : %p\n", &s_l_init);
    printf(" static local uninit : %p\n", &s_l_uinit);
    printf("         const local : %p\n", &c_l);
    
    while(1) ;

    return 0;
}

结果如下:

[Linux] linux中C程序运行时的数据分布_第3张图片


[Linux] linux中C程序运行时的数据分布_第4张图片


上面的数据分为三个部分:

以0x8048为页框地址:全局的const变量,它的地址在代码段中,因为这种变量在编译之后就会替换代码中的值,跟define常量一样。

以0x804a为页框地址:全局的静态变量和非静态变量,局部的静态变量。

以0xbfd50为页框地址:局部变量和局部const变量。


也就是说,对于程序中的变量,只有局部的非静态变量在栈中,全局的const变量已经嵌入代码中,其它类型的数据都放在数据段中。

而对于字符串来说,当定义char *时,实际应该是const char *,它的内容放在代码段中,而指针遍历遵循一般的const规则。

而且,从上面的初始化变量和非初始化变量的地址大小可以看到,初始化变量和非初始化变量确实是分开存放的。

要注意的是,这里说的是linux下的C程序,其它系统下可能不太一样。


参考资料:

http://blog.chinaunix.net/uid-26548237-id-3818734.html

http://blog.csdn.net/embedded_hunter/article/details/6897027

你可能感兴趣的:(Linux,linux)