数据在内存中的存储

  • 数据在内存中的存储
    • 大小端存储
    • 整型提升
    • unsigned无符号数造成死循环
    • 类型定义范围的库函数
    • 浮点型存储
    • CC程序内存的分配
    • const的深度讲解及volatile关键字介绍
    • const 修饰指针的作用

数据在内存中的存储

大小端存储

大端,把一个数字高位字节序的内容存储到低地址,低位字节序内容存储到高地址处

小端,把一个数字高位字节序的内容存储到高地址,低位字节序内容存储到低地址处

判断一个机器是大端还是小端?

  1. 指针判断

    int CheckSys(){
     int a = 1;
     char *p = (char *)&a;      //利用char指针取一字节特性
     return *p;   //小端返回1
    }
  2. 联合体(共用体)

    union Un{
     int a;
     char c;
    };
    int main(){
     union Un un;
     un.a = 1;
     printf("%d\n",un.c);     //公用最低一字节,小端返回1
    }

整型提升

这里首先需要知道的是,例子见前文

无符号和普通的变量定义是一样的,只不过差别在于系统对这块内存空间的识别不同

char a = -1;                  
signed char b = -1;
unsigned char c = -1;
printf("a=%d,b=%d,c=%d",a,b,c);    //-1 -1 255
//11111111 char(-1)的补码
//11111111 11111111 11111111 11111111 有符号数整型提升后的数字
//要看打印(解析)的是多少,再转回原码
//10000000 00000000 00000000 00000001 原码

有符号数高位补符号位,无符号数高位补0。

Char a = -128;
//10000000 00000000 00000000 10000000    原
//11111111 11111111 11111111 01111111
//11111111 11111111 11111111 10000000    补
//存的是补码,低八位 10000000
//整型提升 11111111 11111111 11111111 10000000
printf("%u",a); //打印无符号数FFFFFF80

综合整型提升,计算原反补的题


char a[1000];
int i;
for(i=0; i<1000; i++){
  a[i] = -1-i;
}
printf("%d",strlen(a));        
//分析题目,结果就是问数组到第几个元素是0(\0)
char 类型可以存有符号数 -127 - 128 ,所以当char 存到-129//10000000 000000000 00000000 10000001   -129 原码
//11111111 111111111 11111111 01111110   
//11111111 111111111 11111111 01111111   char取低八位,127

//a[128] = 11111111 ;

//a[129] = 01111111 ; 
//-1 -2 -3 ... -128 127 126 .... 0   
所以打印结果是  128+127 = 255

unsigned无符号数造成死循环

unsigned i;
for(i=9; i>=0; i--){
  //无符号数大于=0 恒成立
  当 i == 0x00000000
     i-- 变成    0xFFFFFFFF 解析为无符号数
}

或者是

unsigned char i = 0;
for(i=0; i<=255; i++){
    //当 i ==11111111
    i++ 变成 00000000  <=255 又开始循环
}

类型定义范围的库函数

整型 limits.h

浮点型 float.h

浮点型存储

float f = 5.5;
// 101.1
科学记数法
1.011 * 2^2
标准
(-1)^0 * 1.011 *2^2
所以应该存的是
0 10000001 01100000000000000000000       //0x40b00000
s     e          m

IEEE754规定存储标准

(-1)^S * M * 2^E

(-1)s表示符号位,当s=0,V为正数;当s=1,V为负数。

M表示有效数字,大于等于1,小于2。

2^E表示指数位,对于8位的E,加上中间数127,11位E+1023

一个极其好的例子

int n = 9;
float *p = (float *)&n;
0 00000000 00000000000000000001010            存储形式
(-1)^0 * 0.0000000000000000001001 * 2^-126    取出(无穷小)特殊情况,e全0,不补1

*p= 9.0;
1001.0      二进制
1.001*2^3   科学计数
0 10000010 00100000000000000000000                 存储形式(不存小数点前面的1,后面补0)
(-1)^0 * 1.00100000000000000000000 * 2^130-127     取出,小数点前面补1

C/C++程序内存的分配

栈区(stack)—  由编译器器自动分配释放 ,存放为运行函数而分配的局部变量,函数参数,返回数据、返回地址等

堆区(heap) —  一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似于链表。动态内存的生存期由程序员决定,如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏。

全局区(静态区)(static)—存放全局变量静态数据、常量。程序结束后由系统释放。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在

文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放

程序代码区—存放函数体(类成员函数和全局函数)的二进制代码

const的深度讲解及volatile关键字介绍

volatile前面说过

volatile 保证内存可见性。每次取变量从内存中取 .在c编译环境,const 从语法层面限制了 变量不可定义,从而可以通过指针修改内存中变量的值。在cpp编译环境,const 会被优化,其值被送往寄存器,从而不可改变。linux环境下可以加 -o2 使gcc编译环境同样优化const。

const int b = 0;
int *p = (int *) &b;
*p = 20;
printf("%d",b);                //不优化结果是20,优化了结果是0
volatile const int b = 0;       //保证每次变量从内存中拿
int *p = (int *) &b;
*p = 20;
printf("%d",b);                //20

即编译时不优化,执行时不缓存,每次需从内存中读出。用于多线程或多CPU编程

const 修饰指针的作用

int * const p = &a; //保护指针p

const int *p = &a; //保护 *p
int a = 0;
int *p = &a;
int* *pp = &p;        //二级指针,指向指针p的地址

const int **pp = &p;
//**pp(a)  a不能通过**pp改变
int * const *pp = &p;
*pp 不能改变
int ** const pp = &p;
 pp 不能改变

你可能感兴趣的:(c/c++编程艺术)