C语言内存分布

C语言内存分布

典型的C语言程序内存表示分区共有5个部分:

  1. 正文段 Text segment
  2. 已初始化数据段(数据段)Initialized data segment
  3. 未初始化数据段(bss)Uninitialized data segment
  4. 堆 Stack
  5. 栈 Heap

具体分布图

各个分区的作用

  • 正文段

    • CPU执行的机器指令部分
    • 通常可共享
    • 常常是只读的
  • 已初始化数据段(数据段)
    • 包含程序中需明确赋初始值的变量
    • 保存已经初始化的全局变量
  • 未初始化数据段(BSS)
    • 在程序开始执行之前,内核将此段中的数据初始化为0或空指针
    • 保存未初始化的全局变量(注意:即使是赋值为0也是未初始化!
    • 存储自动变量及每次函数调用所需保存的信息
    • 每次函数调用时,存放其返回地址及调用者的环境信息(如某些机器寄存器的值)
    • 为最近被调用的函数分配自动变量和临时变量的存储空间
    • 动态存储分配

初始化?

上面提到,对全局变量来说,如果是赋值为0仍是未初始化。下面给出实际实验结果:

示例代码1


#include <stdio.h>

int a;

int main(int argc, char const *argv[])
{
    printf("hello\n");
    return 0;
}

编译后查看内存分布:

示例代码2


#include <stdio.h>

int a = 0;

int main(int argc, char const *argv[])
{
    printf("hello\n");
    return 0;
}

编译后查看内存分布:

可以看到,各个存储区域数值没有变化。

示例代码3


#include <stdio.h>

int a = 1;

int main(int argc, char const *argv[])
{
    printf("hello\n");
    return 0;
}

编译后查看内存分布:

可以看到,对全局变量进行真正的初始化之后,bss少了4个字节,data段多出了4个字节。

关于static的问题

示例代码4

先看看相对上一例子,多了一个局部变量之后的内存分布。


#include <stdio.h>

int a = 1;

int main(int argc, char const *argv[])
{
    int b;
    printf("hello\n");
    return 0;
}

编译后查看内存分布:

可以看到,内存分布是没有变化的,局部变量b会在栈上分配到内存。

示例代码5

如果把b定义成static呢?


#include <stdio.h>

int a = 1;

int main(int argc, char const *argv[])
{
    static int b;
    printf("hello\n");
    return 0;
}

编译后查看内存分布:

可以看到,此时bss上多出了8个字节。

示例代码6

如果给b赋初始值0呢?


#include <stdio.h>

int a = 1;

int main(int argc, char const *argv[])
{
    static int b = 0;
    printf("hello\n");
    return 0;
}

编译后查看内存分布:

可以看到,跟上一个例子相比没有变化,说明跟全局变量一样,static变量赋值为0仍是未初始化。

示例代码7

如果给b赋初始值1呢?


#include <stdio.h>

int a = 1;

int main(int argc, char const *argv[])
{
    static int b = 1;
    printf("hello\n");
    return 0;
}

编译后查看内存分布:

可以看到,bss少了4个字节,而data多了4个字节,说明静态变量和全局变量同理,初始化之后是存在data段中的。

关于static的用处

示例代码8


#include <stdio.h>

int x = 4;

void incre() {
    static int x = 1;
    x *= x + 1;
    printf("%d\n", x);
}

int main(int argc, char const *argv[])
{
    int i;
    for (i = 1; i < x; i++) {
        incre();
    }
    return 0;
}

运行结果为:

可以看到,函数increx的作用域存在于其局部,但是却在每次调用函数的时候沿用之前的值!这是因为static定义的变量是静态变量,有着静态存储位置(变量存储位置固定不动,若在代码中已经初始化则存在于data段,否则存在于bss段),而不是存在于栈上,因此每次调用函数读取到的变量的值都是静态存储区的值。

static的意义:

  1. 全局静态变量

    • 不会被其它文件所访问和修改
    • 其它文件中可以使用相同名字的变量,不会发生冲突
  2. 局部静态变量
    • 可以用作计数器,每次函数调用的时候可以进行计数
  3. 静态函数
    • 其它文件中可以定义相同名字的函数,不会发生冲突
    • 静态函数不能被其它文件所用
    • 静态函数会被分配在一个一直使用的存储器,直到程序退出,避免了调用函数时进栈出栈,提升运行速度

参考书目

  1. Unix环境高级编程(中文第三版)
  2. C primer plus(中文第五版)

参考博客

C语言存储空间布局以及static详解——奔人之旅

原文地址:https://www.cnblogs.com/yanhewu/p/8360541.html

时间: 2024-10-28 23:27:58

C语言内存分布的相关文章

C语言内存布局

典型的C语言的内存分布由以下几块组成: • Test segment                               (文本段) • Initialzed data segment            (初始化数据段) • Uninitialized data segment        (未初始化数据段) • Stack                            (栈) • Heap                                (堆) (图a)一:

C++内存分布 虚表 虚指针(非常重要)

C++内存分布 虚表 虚指针: class Base { public: int m_base; }; class DerivedA: public Base { public: int m_derivedA; }; class DerivedB: public Base { public: int m_derivedB; }; class DerivedC: public DerivedA, public DerivedB { public: int m_derivedC; }; 类结构图:

C++类的内存分布

使用Visual Studio工具来看是类的内存分布 先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 reportAllClassLayout,它可以看到所有相关类的内存布局,如果写上/d1 reportSingleClassLayoutXXX(XXX为类名),则只会打出指定类XXX的内存布局.近期的VS版本都支持这样配置. 下面可以定义一个类,像下面这样: class Base { int a; int b; public: void CommonFunction(); };

[转]C++类内存分布

转自:http://www.cnblogs.com/jerry19880126/p/3616999.html 书上类继承相关章节到这里就结束了,这里不妨说下C++内存分布结构,我们来看看编译器是怎么处理类成员内存分布的,特别是在继承.虚函数存在的情况下. 工欲善其事,必先利其器,我们先用好Visual Studio工具,像下面这样一步一步来: 先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 reportAllClassLayout,它可以看到所有相关类的内存布局,如果写上/d1

C++对象内存分布(2) - 菱形继承(non virtual)

1.前言 本篇文章的所有代码例子,如果是windows上编译运行,则使用的是visual studio 2013.如果是RHEL6.5平台(linux kernal: 2.6.32-431.el6.i686)上编译运行,则其gcc版本为4.4.7,如下所示: [[email protected] ~]# gcc --version gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4) 2.菱形继承类的内存分布 2.1.类的结构 菱形继承 - 重复继承 2.2.实现

《C++反编译与逆向分析技术揭秘》之学习笔记02--结构体和类之内存分布

※结构体和类之内存分布 1.空类的大小空类:其实空类至少会占用1个字节的长度. 2.字节对齐在为结构体和类中的数据成员分配内存时,结构体中的当前数据成员类型长度为M,指定对齐值为N,那么实际对齐值位q=min(M,N),其成员的地址安排在q的倍数上. vc6.0缺省对齐8个字节sShort占用2个字节,所以安排的地址0x0012FF70为2的倍数.nInt占用4个字节,所以安排的地址0x0012FF74为4的倍数.因为结构体中最大的字段长度为4,所以对齐值调整为4个字节.因为test对象为8个字

c语言内存四区模型

c语言内存四区模型:代码区,全局区(常量区),栈区,堆区 在全局区(常量区),两个字符串完全一样c++编译器只会定义一份 char * getBuf() { char buf[20]; strcpy(buf, "abcde"); return buf; } abcdX?  有乱码! 确实把内存地址返回了,但不能用 被调函数调用完毕,在临时区分配的内存统统消失 char *buf= (char *)malloc(sizeof(char)*20); 手动malloc申请一份内存,由程序员手

jvm堆内存分布及gc发生的条件

jvm虚拟机对内存管理主要体现在堆内存的管理上,我们可以在启动jvm的时候设置jvm对内存大小及调整策略. 1.jvm启动参数: -Xms:jvm启动时初始堆大小. -Xmx:jvm堆的最大值. -Xss:线程栈大小. -Dname=value:jvm全局属性设置. jvm启动参数设置有很多,以上只是列举本人接触过的几个参数. 1)首先,-Xms是jvm启动时堆内存的初始大小,当堆内存不够用时,jvm调整堆大小到-Xmx设置的大小.一般resin这些服务器会把-Xms和-Xmx大小设置一样以避免

使用汇编分析c代码的内存分布

arm平台下使用反汇编分析c内存分布: arm:使用arm-linux-objdump命令将编译完成之后的elf文件,进行反汇编. 之后重定向到tmp.s文件中. 第一步变量如下c文件. vim tmp.c #include<stdio.h> #define VAR 0xFF int a = 0; static int b = 0; int c = 10; static int d = 20; const int finalone = 10; const int final; int main