鸿 网 互 联 www.68idc.cn

当前位置 : 主页 > 网络程序脚本 > linux shell > >

C语言程序的存储区域与const关键字的使用方法

来源:互联网 作者:佚名 时间:2015-06-03 08:52
一 C语言程序的存储区域 由C语言代码(文本文件)形成可执行程序(二进制文件) 需要经过编译 汇编 连接三个阶段 编译过程把C语言文本文件生成汇编程序 汇编过程把汇编程序形成二进制机器代码 连接过程则将各个源文件生成的二进制机器代码文件组合成一个文件
C语言程序的存储区域

  由C语言代码(文本文件)形成可执行程序(二进制文件)需要经过编译汇编连接三个阶段编译过程把C语言文本文件生成汇编程序汇编过程把汇编程序形成二进制机器代码连接过程则将各个源文件生成的二进制机器代码文件组合成一个文件

  C语言编写的程序经过编译连接后将形成一个统一文件它由几个部分组成在程序运行时又会产生其他几个部分各个部分代表了不同的存储区域

  >代码段(Code或Text)

  代码段由程序中执行的机器代码组成在C语言中程序语句执行编译后形成机器代码在执行程序的过程中CPU的程序计数器指向代码段的每一条机器代码并由处理器依次运行

  >只读数据段(RO data)

  只读数据段是程序使用的一些不会被更改的数据使用这些数据的方式类似查表式的操作由于这些变量不需要更改因此只需要放置在只读存储器中即可

  >已初始化读写数据段(RW data)

  已初始化数据是在程序中声明并且具有初值的变量这些变量需要占用存储器的空间在程序执行时它们需要位于可读写的内存区域内并且有初值以供程序运行时读写
>未初始化数据段(BBS)

  未初始化数据是在程序中声明但是没有初始化的变量这些变量在程序运行之前不需要占用存储器的空间

  >堆(heap)

  堆内存只在程序运行时出现一般由程序员分配和释放在具有操作系统的情况下如果程序没有释放操作系统可能在程序(例如一个进程)结束后会后内存

  >栈(statck)

  堆内存只在程序运行时出现在函数内部使用的变量函数的参数以及返回值将使用栈空间栈空间由编译器自动分配和释放

  

  代码段只读数据段读写数据段未初始化数据段属于静态区域而堆和栈属于动区域代码段只读数据段和读写数据段将在连接之后产生未初始化数据段将在程序初始化的时候开辟而对堆和栈将在程序饿运行中分配和释放

  C语言程序分为映像和运行时两种状态在编译连接后形成的映像中将只包含代码段(Text)只读数据段(R Data)和读写数据段(RW Data)在程序运行之前将动态生成未初始化数据段(BSS)在程序的运行时还将动态生成堆(Heap)区域和栈(Stack)区域

  注一般来说在静态的映像文件中各个部分称之为节(Section)而在运行时的各个部分称之为段(Segment)如果不详细区分统称为段

  C语言在编译连接后将生成代码段(TEXT)只读数据段(RO Data)和读写数据段(RW Data)在运行时除了上述三个区域外还包括未初始化数据段(BBS)区域和堆(heap)区域和栈(Stack)区域

C语言程序的段

  段的分类

  每一个源程序生成的目标代码将包含源程序所需要表达的所有信息和功能目标代码中各段生成情况如下

  >代码段(Code)

  代码段由程序中的各个函数产生函数的每一个语句将最终经过编译和汇编生成二进制机器代码

  >只读数据段(RO Data)

  只读数据段由程序中所使用的数据产生该部分数据的特点在运行中不需要改变因此编译器会将数据放入只读的部分中C语言的一些语法将生成只读数据数据段

    只读数据段(RO Data)

  只读数据段(RO Data)由程序中所使用的数据产生该部分数据的特点是在运行中不需要改变因此编译器会将数据放入只读的部分中以下情况将生成只读数据段

  n  只读全局变量

  定义全局变量const  char a[]=abcdefg将生成大小为个字节的只读数据区并使用字符串abcdefg初始化如果定义为const char a[]=abcdefg没有指定大小将根据abcdefgh字串的长度生成个字节的只读数据段

  n  只读局部变量

  例如在函数内部定义的变量const char  b[]=;其初始化的过程和全局变量

  n  程序中使用的常量

  例如在程序中使用printf(information\n)其中包含了字串常量编译器会自动把常量information \n放入只读数据区

  注在const  char a[]={ABCDEFG}中定义了个字节的数据区但是只初始化了前面的个字节(个字符和表示结束符的\在这种用法中实际后面的字节米有初始化但是在程序中也不能写实际上没有任何用处因此在只读数据段中一般都需要做完全的的初始化

  读写数据段(RW Data)

  读写数据段表示了在目标文件中一部分可以读也可以写的数据区在某些场合它们又被称为已初始化数据段这部分数据段和代码与只读数据段一样都属于程序中的静态区域但是具有科协的特点

  n  已初始化全局变量

  例如在函数外部定义全局的变量char  a[]=abcdefg

  n  已初始化局部静态变量

  例如在函数中定义static  char b[]=函数中由static定义并且已经初始化的数据和数组将被编译为读写数据段

  说明

  读写数据区的特点是必须在程序中经过初始化如果只有定义没有初始值则不会生成读写数据区而会定义为未初始化数据区(BSS)如果全局变量(函数外部定义的变量)加入static修饰符写成static  char a[]的形式这表示只能在文件内部使用而不能被其他文件使用

  未初始化数据段(BSS)

  未初始化数据段常被称之为BSS(英文名为Block start by symbol的缩写)与读写数据段类似它也属于静态数据区但是该段中数据没有经过初始化因此它只会在目标文件中被标识而不会真正称为目标文件中的一个段该段将会在运行时产生未初始化数据段只有在运行的初始化阶段才会产生因此它的大小不会影响目标文件的大小

在C语言的程序中对变量的使用还有以下注意

  在函数体中定义的变量通常是在栈上不需要在程序中进行管理由编译器处理

  用malloccallocrealoc等分配分配内存的函数所分配的内存空间在堆上程序必须保证在使用后使用后freee释放否则会发生内存泄漏

  所有函数体外定义的是全局变量加了static修饰符后的变量不管在函数内部或者外部存放在全局区(静态区)

  使用const定义的变量将放于程序的只读数据区

  说明

  在C语言中可以定义static变量在函数体内定义的static变量只能在该函数体内有效在所有函数体外定义的static变量也只能在该文件中有效不能在其他源文件中使用对于没有使用static修饰的全局变量可以在其他的源文件中使用这些区别是编译的概念即如果不按要求使用变量编译器会报错使用static 和没使用static修饰的全局变量最终都将放置在程序的全局去(静态去)

程序中段的使用

  C语言中的全局区(静态区)实际上对应着下述几个段

  只读数据段:R Data

  读写数据段RW Data

  未初始化数据段BSS Data

  一般来说直接定义的全局变量在未初始化数据区如果该变量有初始化则是在已初始化数据区(RW Data)加上const修饰符将放置在只读区域(R Data)

  eg:

  const char ro[]=this  is a readonlydata;//只读数据段不能改变ro数组中的内容ro存放在只读数据段

   char  rw[]=this is global readwrite data;//已初始化读写数据段可以改变数组rw中的内容应为数值是赋值不是把this is  global readwrite data 地址给了rw不能改变this is global readwrite data的数值因为起是文字常量放在只读数据段中

  char  bss_[];//未初始化数据段

  const char  *ptrconst = constant data;//constant  data放在只读数据段不能改变ptrconst中的值因为其是地址赋值ptrconst指向存放constant data的地址其为只读数据段但可以改变ptrconst地址的数值因其存放在读写数据段中

  int main()

  {

           short  b;//b放置在栈上占用个字节

           char   a[];//需要在栈上开辟个字节a的值是其首地址

  chars[]=abcde;//s在栈上占用个字节abcde本身放置在只读数据存储区字节s是一个地址常量不能改变其地址数值即s++是错误的

           char*p;//p在栈上占用个字节

           char*p =;//放置在只读数据存储区个字节p在栈上p指向的内容不能更改但是p的地址值可以改变即p++是对的

           static  char bss_[];//局部未初始化数据段

           static  int   c= ;//局部(静态)初始化区

           p = (char *)malloc(*sizeof(char));//分配的内存区域在堆区

           strcpy(pxxx);//xxx放置在只读数据存储区个字节

           free(p);//使用free释放p所指向的内存

           return ;

  }

  说明

  只读数据段需要包括程序中定义的const型的数据(如const  char ro[])还包括程序中需要使用的数据如对于const  char ro[]和const char * ptrconst的定义它们指向的内存都位于只读数据据区其指向的内容都不允许修改区别在于前者不允许在程序中修改ro的值后者允许在程序中修改ptrconst本身的值对于后者改写成以下的形式将不允许在程序中修改ptrconst本身的值

                     const  char * const ptrconst =  const  data;

  读写数据段包含了已经初始化的全局变量static  char rw[]以及局部静态变量static char

  rw[]rw和rw的差别在于编译时是在函数内部使用的还是可以在整个文件中使用对于前者static修饰在于控制程序的其他文件时候可以访问rw变量如果有static修饰将不能在其他的C语言源文件中使用rw这种影响针对编译连接的特性但无论有static变量rw都将被放置在读写数据段对于后者rw它是局部的静态变量放置在读写数据区如果不使用static修饰其意义将完全改变它将会是开辟在栈空间局部变量而不是静态变量

  未初始化数据段事例中的bss_[]和bss_[]在程序中代表未初始化的数据段其区别在于前者是全局的变量在所有文件中都可以使用后者是局部的变量只在函数内部使用未初始化数据段不设置后面的初始化数值因此必须使用数值指定区域的大小

  编译器将根据大小设置BBS中需要增加的长度

  栈空间包括函数中内部使用的变量如short b和char  a[]以及char *p中p这个变量的值

  》变量p指向的内存建立在堆空间上堆空间只能在程序内部使用但是堆空间(例如p指向的内存)可以作为返回值传递给其他函数处理

  》栈空间主要用于以下类数据的存储

  a函数内部的动态变量

  b函数的参数

  c函数的返回值

  》栈空间主要的用处是供函数内部的动态变量使用变量的空间在函数开始之前开辟在函数退出后由编译器自动回收

  看一个事例

  #include<stdioh>

  

  int main()

  {

           char*p =tiger;

           p[]=I;

           p++;

           printf(%s\np);

  }

  编译后提示段错误

  分析

  char *p =tiger;系统在栈上开辟了个字节存储p的数值tiger在只读存储区中存储因此tiger的内容不能改变*p=tiger表示地址赋值因此p指向了只读存储区因此改变p指向的内容会引起段错误但是因为p是存放在栈上因此p的数值是可以改变的因此p++是正确的

nst的使用

  前言

  const是一个C语言的关键字它限定一个变量不允许被改变使用const在一定程序上可以提高程序的健壮性另外在观看别人代码的时候清晰理解const所起的作用对理解被人的程序有所帮助

  nst变量和 常量

  ()const修饰的变量其值存放在只读数据段中起值不能被改变称为只读变量

  其形式为 const  int a=;此处可以用a代替

  ()常量其也存在只读数据段中其数值也不能被改变其形式为abc

  nst 变量和const限定的内容

  先看一个事例

  #include<stdioh>

  typedef   char *pStr;

  intmain()

  {

           char       string[] = tiger;

           const       char*p = string;

           const   pStr  p = string;

           p++;

           p++;

           printf(p=%s\np=%s\npp);

  

  }

  程序经过编译后提示错误为

  error:increment  of readonly  variable p

  >const 使用的基本形式为const char m;

  限定m 不可变

  >替换式中的mconst char *pm;

  限定*pm不可变当然pm是可变的因此p++是对的

  >替换式中的charconst newType m;

  限定m不可变问题中的pStr是一种新类型因此问题中p不可变p++是错误的

  ()const 和指针

  类型声明中const用来修饰一个常量有如下两种写法

  >const在前面

  const  int   nValue;//nValue是const

  const char  *pContent;//*pContent是constpConst可变

  const (char *)pContent;//pContent是const*pContent可变

  char  *const  pContent;//pContent是const*pContent可变

  const char * const  pContent;//pContent和*pContent都是const

  >const 在后面与上面的声明对等

  int const nValue // nValue是const

    char const * pContent;//*pContent是const    pContent可变

    (char *) constpContent;//pContent是const    *pContent可变

    char* const pContent;// pContent是const     *pContent可变

    char const* const pContent;//pContent和*pContent都是const

  说明const和指针一起使用是C语言中一个很常见的困惑之处下面是两天规则

  ()沿着*号划一条线如果const位于*的左侧则const就是用来修饰指针所指向的变量即指针指向为常量如果const位于*的右侧const就是修饰指针本身即指针本身是常量你可以根据这个规则来看上面声明的实际意义相信定会一目了然

  ()对于const (char *) ; 因为char *是一个整体相当于一个类型(如char)因此这是限定指针是const

网友评论