0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

在C和C++语言开发中内存直接操作的方法

C语言编程基础 来源:未知 作者:李倩 2018-05-09 10:56 次阅读

在C和C++语言开发中,指针、内存一直是学习的重点。因为C语言作为一种偏底层的中低级语言,提供了大量的内存直接操作的方法,这一方面使程序的灵活度最大化,同时也为bug埋下很多隐患。

因此,无论如何,我们都要对内存有一个清晰的理解。

一、对内的分配

32位操作系统支持4GB内存的连续访问,但通常把内存分为两个2GB的空间,每个进程在运行时最大可以使用2GB的私有内存(0x00000000—0x7FFFFFFF)。即理论上支持如下的大数组:

char szBuffer[2*1024*1024*1024];

当然,由于在实际运行时,程序还有代码段、临时变量段、动态内存申请等,实际上是不可能用到上述那么大的数组的。

至于高端的2GB内存地址(0x80000000—0xFFFFFFFF),操作系统一般内部保留使用,即供操作系统内核代码使用。在Windows和Linux平台上,一些动态链接库(Windows的dll,Linux的so)以及ocx控件等,由于是跨进程服务的,因此一般也在高2GB内存空间运行。

可以看到,每个进程都能看到自己的2GB内存以及系统的2GB内存,但是不同进程之间是无法彼此看到对方的。当然,操作系统在底层做了很多工作,比如磁盘上的虚拟内存交换(请看下以标题),不同的内存块动态映射等等。

二、虚拟内存

虚拟内存的基本思想是:用廉价但缓慢的磁盘来扩充快速却昂贵的内存。在一定时刻,程序实际需要使用的虚拟内存区段的内容就被载入物理内存中。当物理内存中的数据有一段时间未被使用,它们就可能被转移到硬盘中,节省下来的物理内存空间用于载入需要使用的其他数据。

在进程执行过程中,操作系统负责具体细节,使每个进程都以为自己拥有整个地址空间的独家访问权。这个幻觉是通过“虚拟内存”实现的。所有进程共享机器的物理内存,当内存使用完时就用磁盘保存数据。在进程运行时,数据在磁盘和内存之间来回移动。内存管理硬件负责把虚拟地址翻译为物理地址,并让一个进程始终运行于系统的真正内存中,应用程序员只看到虚拟地址,并不知道自己的进程在磁盘与内存之间来回切换。

从潜在的可能性上说,与进程有关的所有内存都将被系统所使用,如果该进程可能不会马上运行(可能它的优先级低,也可能是它处于睡眠状态),操作系统可以暂时取回所有分配给它的物理内存资源,将该进程的所有相关信息都备份到磁盘上。

进程只能操作位于物理内存中的页面。当进程引用一个不在物理内存中的页面时,MMU就会产生一个页错误。内存对此事做出响应,并判断该引用是否有效。如果无效,内核向进程发出一个“segmentation violation(段违规)”的信号,内核从磁盘取回该页,换入内存中,一旦页面进入内存,进程便被解锁,可以重新运行——进程本身并不知道它曾经因为页面换入事件等待了一会。

三、内存的使用

对于程序员,我们最重要的是能理解不同进程间私有内存空间的含义。C和C++的编译器把私有内存分为3块:基栈、浮动栈和堆。如下图:

(1)基栈:也叫静态存储区,这是编译器在编译期间就已经固定下来必须要使用的内存,如程序的代码段、静态变量、全局变量、const常量等。

(2)浮动栈:很多书上称为“栈”,就是程序开始运行,随着函数、对象的一段执行,函数内部变量、对象的内部成员变量开始动态占用内存,浮动栈一般都有生命周期,函数结束或者对象析构,其对应的浮动栈空间的就拆除了,这部分内容总是变来变去,内存占用也不是固定,因此叫浮动栈。

(3)堆:C和C++语言都支持动态内存申请,即程序运行期可以自由申请内存,这部分内存就是在堆空间申请的。堆位于2GB的最顶端,自上向下分配,这是避免和浮动栈混到一起,不好管理。我们用到malloc和new都是从堆空间申请的内存,new比malloc多了对象的支持,可以自动调用构造函数。另外,new创建对象,其成员变量位于堆里面。

我们来看一个例子:

constintn=100;

voidFunc(void)

{

charch=0;

char*pBuff=(char*)malloc(10);

//…

}

这个函数如果运行,其中n由于是全局静态变量,位于基栈,ch和pBuff这两个函数内部变量,ch位于浮动栈,而pBuff指向的由malloc分配的内存区,则位于堆栈。

在内存理解上,最著名的例子就是线程启动时的参数传递。

函数启动一个线程,很多时候需要向线程传参数,但是线程是异步启动的,即很可能启动函数已经退出了,而线程函数都还没有正式开始运行,因此,绝不能用启动函数的内部变量给线程传参。道理很简单,函数的内部变量在浮动栈,但函数退出时,浮动栈自动拆除,内存空间已经被释放了。当线程启动时,按照给的参数指针去查询变量,实际上是在读一块无效的内存区域,程序会因此而崩溃。

那怎么办呢?我们应该直接用malloc函数给需要传递的参数分配一块内存区域,将指针传入线程,线程收到后使用,最后线程退出时,free释放。

我们来看例子:

//这个结构体就是参数表

typedefstruct_CListen_ListenAcceptTask_Param_

{

Linux_Win_SOCKETm_nSocket;

//其他参量… …

}SCListenAcceptTaskParam;

//习惯性写法,设置结构体后,立即声明结构体的尺寸,为后续malloc提供方便

constULONGSCListenAcceptTaskParamSize=sizeof(SCListenAcceptTaskParam);

//这里接收到连接请求,申请参数区域,将关键信息带入参数区域,帮助后续线程工作。

boolCListen::ListenTaskCallback(void*pCallParam,int&nStatus)

{

//正常的函数逻辑… …

//假定s是accept到的socket,需要传入后续线程工作

//在此准备一块参数区域,从远堆上申请

SCListenAcceptTaskParam*pParam=(SCListenAcceptTaskParam*)malloc(SCListenAcceptTaskParamSize);

//给参数区域赋值

pParam->m_nSocket=s;

//此处启动线程,将pParam传递给线程… …

//正常的函数逻辑… …

}

//这是线程函数,负责处理上文accept到的socket

boolCListen::ListenAcceptTask(void*pCallParam,int&nStatus)

{

//第一句话就是强制指针类型转换,获得外界传入的参数区域

SCListenAcceptTaskParam*pParam=(SCListenAcceptTaskParam*)pCallParam;

//正常的函数逻辑… …

//退出前,必须要做的工作,确保资源不被泄露

close(pParam->m_nSocket);//关闭socket

free(pCallParam);// free传入的参数区域

//… …

}

四、内存 bug

无规则的滥用内存和指针会导致大量的bug,程序员应该对内存的使用保持高度的敏感性和警惕性,谨慎地使用内存资源。

使用内存时最容易出现的bug是:

(1)坏指针值错误:在指针赋值之前就用它来引用内存,或者向库函数传送一个坏指针,第三种可能导致坏指针的原因是对指针进行释放之后再访问它的内容。可以修改free语句,在指针释放之后再将它置为空值。

free(p); p = NULL;

这样,如果在指针释放之后继续使用该指针,至少程序能在终止之前进行信息转储。

(2)改写(overwrite)错误:越过数组边界写入数据,在动态分配的内存两端之外写入数据,或改写一些堆管理数据结构(在动态分配内存之前的区域写入数据就很容易发生这种情况)

p = malloc(256); p[-1] = 0; p[256] = 0;

(3)指针释放引起的错误:释放同一个内存块两次,或释放一块未曾使用malloc分配的内存,或释放仍在使用中的内存,或释放一个无效的指针。一个极为常见的与释放内存有关的错误就是在 for(p=start;p=p->next) 这样的循环中迭代一个链表,并在循环体内使用 free(p) 语句。这样,在下一次循环迭代时,程序就会对已经释放的指针进行解除引用操作,从而导致不可预料的结果。

我们可以这样迭代:

structnode *p,*tart,*temp;

for(p=start;p;p=temp)

{

temp=p->next;

free(p);

}

总结:这些知识都是本人最近看书总结出来的,可能有很多是个人主观,欢迎拍砖…

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内存
    +关注

    关注

    8

    文章

    3023

    浏览量

    74029
  • C语言
    +关注

    关注

    180

    文章

    7604

    浏览量

    136761
  • C++
    C++
    +关注

    关注

    22

    文章

    2108

    浏览量

    73636

原文标题:程序员对内存的理解

文章出处:【微信号:xx-cyy,微信公众号:C语言编程基础】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    C语言C++那些不同的地方

    ++11标准。根据不同的标准,它们的功能也会有所不同,但是越新的版本支持的编译器越少,所以本文讨论的时候使用的C语言标准是C89,C++
    的头像 发表于 12-07 14:29 950次阅读
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>和<b class='flag-5'>C++</b><b class='flag-5'>中</b>那些不同的地方

    JAVA和C++区别

    指针来直接访问内存无指针,并且增添了自动的内存管理功能,从而有效地防止了cc++语言中指针
    发表于 04-11 15:19

    JAVA和C++区别

    直接访问内存无指针,并且增添了自动的内存管理功能,从而有效地防止了cc++语言中指针
    发表于 10-10 14:50

    Java和C++的区别

    直接访问内存无指针,并且增添了自动的内存管理功能,从而有效地防止了cc++语言中指针
    发表于 09-13 16:02

    嵌入式开发为什么选择C++语言

    一、C++概述1.嵌入式开发为什么选择C++语言?(1)面向过程编程的特点C
    发表于 10-27 08:25

    C语言C++运用

    ,一般将硬件初始化的工作交给汇编,比较复杂的操作交给C语言。③C语言具有很高的运行效率。2.嵌入式开发
    发表于 11-25 10:47

    CodeWarrior C and C++ and Assembly 语言参考设计

    本文是英文版的,介绍了CodeWarrior C and C++ and Assembly 语言参考设计,您的设计或许有用:
    发表于 06-22 15:33 74次下载

    浅谈关于DSP6000C/C++语言和汇编语言的混合编程的方法

    一、混合编程的方法主要有以下几种: (1)独立编写C语言程序和汇编程序,分别编译形成各自的目标代码块, 然后用连接器将两种模块连接起来。 (2)直接
    发表于 10-24 10:10 1次下载

    C++内存泄漏分析方法

    C++是一种非常流行的计算机编程语言使用的过程容易出现内存泄漏问题,而该问题往往难以识别。给出了一种对
    发表于 11-23 11:19 5次下载
    <b class='flag-5'>C++</b><b class='flag-5'>内存</b>泄漏分析<b class='flag-5'>方法</b>

    C语言C++相互调用

        1CC++相互调用 一个嵌入式系统中大部分的底层和驱动层更多的是采用C语言来进行开发
    的头像 发表于 01-18 11:05 3330次阅读
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>与<b class='flag-5'>C++</b>相互调用

    嵌入式C++开发详解

    一、C++概述1.嵌入式开发为什么选择C++语言?(1)面向过程编程的特点C
    发表于 10-20 20:21 15次下载
    嵌入式<b class='flag-5'>C++</b><b class='flag-5'>开发</b>详解

    constC语言C++的区别与使用!

    被const修饰的全局变量不能以地址的形式进行修改,由于它在内存位于常量区,他的地址空间是只读的。C语言中被const的变量是
    的头像 发表于 04-24 16:08 1382次阅读

    C++之父:Rust等内存安全语言的安全性并不优于C++

    现在,如果我认为这些 "安全" 语言中的任何一种我关心的使用范围内都比 C++ 优越,我就不会认为 C/C++ 的淡出是一件坏事,但事实并
    的头像 发表于 02-06 10:22 1209次阅读

    如何选择创建c语言c++

    的详尽、详实、细致的讨论。 C 语言的特点和优势: C 语言是一种过程性的编程语言,它注重的是简洁、高效、
    的头像 发表于 11-27 15:58 604次阅读

    c语言,c++,java,python区别

    C语言C++、Java和Python是四种常见的编程语言,各有优点和特点。 C语言
    的头像 发表于 02-05 14:11 2380次阅读