定义一个变量:存储类型  数据类型  变量名

存储类型(变量存储的位置):auto、register、static、extern

1、auto:对于局部变量,atuo可以缺省。位置:栈

2、extern:用来声明全局变量(在当前文件被引用,在其他文件中定义);对于函数,extern可以缺省。位置:初始化的全局变量位于数据段,未初始化的位于bss段。

3、register: 用来定义频繁被使用的变量(局部、整形、字符型),位置:寄存器

4、static:同extern可以修饰变量和函数。修饰变量分为静态全局变量和函数体内的静态变量;位置:初始化的全局变量位于数据段,未初始化的位于bss段。

5、const: 保护传参数时,原数据不被修改。位置:局部常量位于栈,全局常量位于代码段。

6、volatile:

7、enum: 应对一个变量可能存在多个值,枚举类型即将变量所有可能的值(枚举值)一一列举出来。

(1)定义枚举类型:“enum 类型名{枚举值1,枚举值2,……,枚举值n}”。

(2)定义枚举变量:“enum 类型名 变量名”,或者“类型名 变量名”。

(3)枚举值是常量、只能将枚举值赋给枚举变量、枚举值可以是有意义的字符串、枚举值默认从0开始递增。

eg:

enum week{Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday};

enum week day1,day2;

day1 = Wednesday;(day1为2)

8、union: 公用体类似结构体可以定义多个成员变量,但与结构体不同的是共用体共享同一段内存空间,即在某一时刻只能存储其中的一个成员。

eg:

union fun1{

char a[10]; //10字节

double b; //8字节

}

fun1占16个字节(double为union中最大的数据类型,根据内存对齐,空间大小要为8的整数倍)

union fun2{

char a; //1字节

double b; //8字节

}

fun2占8字节

union{

int i;

char a[2];

} u;

u.a[0] = 0x39;

u.a[1] = 0x38;

u.i 的值应该为多少呢?

这里需要考虑存储模式:大端模式和小端模式。

大端模式(Big_endian):字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。

小端模式(Little_endian):字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中。

union 型数据所占的空间等于其最大的成员所占的空间。对union 型的成员的存取都是相对于该联合体基地址的偏移量为0 处开始,也就是联合体的访问不论对哪个变量的存取都是从union 的首地址位置开始。

判断大端模式:

int checkSystem( )

{

   union check

   {

      int i;

      char ch;

   } c;

   c.i = 1;

   return (c.ch ==1);

}

9、typedef:

#include <stdio.h>

int add(int a , int b){

Return a+b;

}

void main(){

int (*fun)(int) = (int (*)(int) )add;

int r = fun(20); //正确

//int r = fun(20,30,40);  //正确

printf(“%d\n”,r);

}

函数调用后,在栈中为它的参数分配空间,用实参去初始化形参。上面代码,只为第一个参数初始化,第二个参数没有初始化为随机值。

总结:

1、函数执行的时候有自己的临时栈空间。

2、函数的参数就在临时栈中。如果函数传递实参,则用来初始化临时参数变量。

3、参数传递方式:按值传递、按地址传递、按引用传递

4、函数返回:通过参数返回、通过返回值返回。

_stdcall、_cdecl、_fastcall 函数修饰属性,3种调用方式

int  _attribute_((stdcall)) add(int , int);  //linux

int  _stdcall add(int,int); //windows

通过gcc -S查看汇编,可以看出差异。

_cdecl:所有参数从右到左依次入栈,由调用者负责把参数压入栈,最后也是由调用者负责清除栈的内容

_stdcall:所有参数从右到左依次入栈,由调用者负责把参数压入栈,最后由被调用者负责清除栈的内容

1、决定函数参数压栈顺序

2、决定函数栈清空方式

3、windows里将决定了函数的名字转换

Windows中cl编译命令、link连接命令

far、near、huge指针。far指的是16位寻址、far是32位寻址、huge是综合。

虚拟内存:

问题:

#include <stdio.h>

#include <stdlib.h>

main(){

int * a = malloc(4);

*a=9999;

printf(“%p\n”,a);

while(1);

}

#include <stdio.h>

#include <stdlib.h>

main(){

int * a = 第一个程序中开辟空间的地址;

printf(“%p\n”,a);

while(1);

}

问:会不会打印出9999?

结果:出现段错误

#include <stdio.h>

#include <stdlib.h>

main(){

int * p = malloc(0);

*p=9999;

printf(“%d\n”,*p);

}

问:会不会出现段错误

结果:打印9999

一个程序不能访问另外一个程序的地址指向的空间。

1、每个程序的开始地址都是0x080084000

2、程序中使用的地址都是逻辑地址,仅仅是个编号,用int来表示(32位机,寻址空间4G)。

3、每个程序提供了4G访问能力

4、逻辑地址与物理地址进行关联才有意义,这个过程称为内存映射

5、虚拟内存的提出,禁止用户直接访问物理地址,有助于系统的稳定。

6、以4K(16进制1000)为基本单位进行映射,称为内存页。需要分配4个字节,也会映射4K的空间。

段错误:无效访问,访问超出了该进程所能访问的空间。

非法访问:比如malloc分配的空间之外的空间可以访问,但是非法访问。

虚拟内存分配:

栈:编译器自动生成代码负责维护

堆:地址是否映射,映射的空间是否被管理

1、brk/sbrk  内存映射函数

int brk(void * end);

void *sbrk(int size);

#include <stdio.h>

#include <unistd.h>

void main(){

int *p = sbrk(4); //分配4个字节空间

*p = 8888;

printf(“%d\n”,*p);

}

#include <stdio.h>

#include <unistd.h>

void main(){

int *p = sbrk(0); //虚拟地址的首地址

*p = 8888;

printf(“%d\n”,*p);

}

结果:段错误

#include <stdio.h>

#include <unistd.h>

void main(){

int *p = sbrk(0); //虚拟地址的首地址

brk(p+1);

*p = 8888;

printf(“%d\n”,*p);

}

结果:没问题

#include <stdio.h>

#include <unistd.h>

void main(){

int *p = sbrk(0); //虚拟地址的首地址

brk(p+1);

*p = 8888;

brk(p);

*p = 999;

printf(“%d\n”,*p);

}

结果:段错误

应用:

1、sbrk分配空间

2、sbrk得到没有映射的虚拟地址

3、brk分配空间

4、brk释放空间

sbrk与brk后台系统维护一个指针,指针默认是null。

调用sbrk,判定指针是否是0,是:返回空闲首地址(空间为4K的倍数)初始化该指针,并且把指针位置+size。否:直接返回指针,并且把指针位置+size

sbrk控制起始端

brk控制末端

应用案例:

写一个程序查找1-10000之间所有的素数。并且存放到缓冲,然后打印

缓冲的实现使用sbrk/brk

对比:

new、malloc、brk/sbrk、stl、智能指针

异常处理:

int brk(void *)

void * sbrk(int)

如果成功:brk返回0,sbrk返回指针

如果失败:brk返回-1,sbrk返回(void*)-1

unix函数出错以后,修改内部变量:errno

#include <errno.h>

输出错误原因:

(1)perror  #include<stdlib.h> 参数 s 所指的字符串会先打印出,后面再加上错误原因字符串

范例

#include<stdio.h>

intmain(void){

FILE*fp;

fp=fopen("/root/noexitfile","r+");

if(NULL==fp){

perror("/root/noexitfile");

}

return0;

}

运行结果

[root@localhost io]# gcc perror.c

[root@localhost io]# ./a.out

/root/noexitfile: No such file or directory

(2)printf(“%m”);

(3)首先extern int errno  然后 printf(“%s”,strerror(errno));

Linux--变量与虚拟内存的更多相关文章

  1. Linux进程的虚拟内存区域划分

    Linux进程的虚拟内存区域分为:代码区.只读常量区.全局区.BSS段.堆区.栈区 代码区:存储功能代码,函数名所在的区域 只读常量区:存放字符串常量,以及const修饰的全局变量 全局区/数据区:存 ...

  2. linux变量心得

    前一段时间学习了一下linux的变量,现在总结有3点需要特别注意: linux变量和C/C++变量的区别 linux变量的引用 linux变量特有的命令替换 先说第一点,linux变量更像是宏定义,只 ...

  3. linux --> Linux变量之$#, $*, $@含义

    Linux变量之$#, $*, $@含义 一.介绍 $# //是传给脚本的参数个数 $ //是脚本本身的名字 $1 //是传递给该shell脚本的第一个参数 $ //是传递给该shell脚本的第二个参 ...

  4. Linux系统实现虚拟内存有两种方法:交换分区(swap分区)和交换文件

    Linux系统实现虚拟内存有两种方法:交换分区(swap分区)和交换文件 交换文件 查看内存:free -m , -m是显示单位为MB,-g单位GB 创建一个文件:touch /root/swapfi ...

  5. Linux进程的虚拟内存

    简介 用户进程的虚拟地址空间是Linux的一个重要的抽象:它为每个运行进程提供了同样的系统视图,这使得多个进程可以同时运行,而不会干扰到其他进程内存中的内容. 每个应用程序都有自己的线性地址空间,与所 ...

  6. 为linux系统添加虚拟内存swap分区

    阿铭linux学习笔记之swap分区 一.作用: swap分区是交换分区,在系统物理内存不足时与swap进行交换,对web服务器的性能影响极大,通过调整swap分区大小来提升服务器的性能,节省资源费用 ...

  7. Linux设置Swap虚拟内存方法

    linux可以文件或者分区来当作虚拟内存. 首先查看当前的内存和swap 空间大小(默认单位为k, -m 单位为M): free -m 查看swap信息,包括文件和分区的详细信息 swapon -s或 ...

  8. Java程序在Linux上运行虚拟内存耗用很大

    突然集群的2个节点挂了,通过top查看, 虚拟内存22G, 通过 pmap -x 8 | grep anon 一大堆64M Linux下glibc的内存管理机制用了一个很奇妙的东西,叫arena.在g ...

  9. Linux记录-Linux Swap分区虚拟内存相关解决方案

    Swap用途:Swap意思是交换分区,通常我们说的虚拟内存,是从硬盘中划分出的一个分区.当物理内存不够用的时候,内核就会释放缓存区(buffers/cache)里一些长时间不用的程序,然后将这些程序临 ...

  10. Linux变量及运算

    变量赋值:var=var_value 变量引用:$var 算术运算:var=`expr $var1 + $var2` 字符串连接:var=str$var1 数值比较:-eq/-ne/-gt/-lt/- ...

随机推荐

  1. onkeyup,onkeydown和onkeypress

    如下一段代码: <html> <script>  function checkForm(){   if(event.keyCode ==13){     event.keyCo ...

  2. 【LeetCode 1】算法修炼 --- Two Sum

    Question: Given an array of integers, find two numbers such that they add up to a specific target nu ...

  3. Android之旅:梦想、学习、坚持、自信、淡定

    前段时间参加了2012年度IT博客大赛,进了前十强,写了一篇获奖感言,不过还没正式在CSDN发表出来.眼看2012年就要结束了,刚好借这个机会将2012年度IT博客大十强获奖感言发表出来,也算是对20 ...

  4. webSocket开源框架:SocketRocket 简单的使用

    需要用到webSocket,所以搜集了一下使用方法, git下载地址:square/SocketRocket gitHUB 上没有看懂,就要 cocoaPod 导入了 socketRocket 导入这 ...

  5. centos安装ruby on rails

      最近研究svn使用http协议,但网上大多都是apache整合svn,我不想使用apache+svn,google翻了很多页终于让我找到了,但要求先安装ruby on rails,所以就有了下面的 ...

  6. ubuntu创建、删除文件及文件夹,强制清空回收站方法

    mkdir 目录名         => 创建一个目录 rmdir 空目录名      => 删除一个空目录 rm 文件名 文件名   => 删除一个文件或多个文件 rm –rf 非 ...

  7. apply和call的区别在哪里

    apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性. Function.apply(obj,args)方法能接收两个参数obj:这个对象将代替Function类里this对象args:这 ...

  8. 20145102 Java 实验一

    20145102 Java 实验一 Java环境的安装 就像第一周写的一样,在linux下java的安装和配置简直简单的不行不行的,一个命令足以: sudo pacman -S jdk 配置什么的也就 ...

  9. Kinect For Windows V2开发日志四:使用OpenCV显示深度图像

    代码示例: #include <Kinect.h> #include <iostream> #include <opencv2\highgui.hpp> using ...

  10. Android 使用动态加载框架DL进行插件化开发

    http://blog.csdn.net/t12x3456/article/details/39958755/ 转载自: 时之沙: http://blog.csdn.net/t12x3456