大端与小端


前面我们提到了依据CPU端模式的不同,数据的存储顺序也不一样。

采用大小模式对数据进行存放的主要区别在于在存放的字节顺序,BE big-endian 大端模式 ,最直观的字节序 ,地址低位存储值的高位,地址高位存储值的低位 ,不需要考虑对应关系,只需要把内存地址从左到右按照由低到高的顺序写出 ,把值按照通常的高位到低位的顺序写出 ,两者对照,一个字节一个字节的填充进去

LE little-endian 小端模式,最符合人的思维的字节序,地址低位存储值的低位,地址高位存储值的高位 ,怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说,低位值小,就应该放在内存地址小的地方,也即内存地址低位 反之,高位值就应该放在内存地址大的地方,也即内存地址高位。

具体参照深入理解计算机系统-之-数值存储(一)-CPU大端和小端模式详解

打印变量的的每一个字节


算法分析


但是理论我们已经讲的很详细了,却没有真正看过数据的存储结果,因此我们期待能够利用C语言编写程序输出变量的的每一位

思路:

C语言中char 必须对应一个byte , 所以它的类型固定是1个字节。

用一个char*的指针指向变量的首地址,往后顺序读取sizeof个字节的数据,就可以访问到变量的每一位

/*
addr  -=> 待打印的变量的首地址
size  -=>·待打印的变量的大小
return 成功返回打印的字节数
*/
int print_all_byte(void *addr, int size)
{unsigned char *ptr = (unsigned char *)addr;int print_bytes = 0;if(ptr == NULL){return -1; }while(print_bytes < size){printf("%02x", *ptr); ptr++; print_bytes++; }printf("\n"); return print_bytes;
}

示例程序


首先我们判断一下当前电脑的大小端模式,然后分别定义了short,int,long,float,double,array数组几种类型的数据。
然后分别打印了它的每一个字节的信息。

#include <stdio.h>
#include <stdlib.h>int check_end()
{int   i = 0x12345678;char *c = (char *)&i; return (*c == 0x12);
}int CheckEnd()
{union{int a;char b;}u;u.a = 1;if (u.b == 1)return 0;else return 1;
}/*
addr  -=> 待打印的变量的首地址
size  -=>·待打印的变量的大小
return 成功返回打印的字节数
*/
int print_all_byte(void *addr, int size)
{unsigned char *ptr = (unsigned char *)addr;int print_bytes = 0;if(ptr == NULL){return -1; }while(print_bytes < size){printf("%02x", *ptr); ptr++; print_bytes++; }printf("\n"); return print_bytes;
}int main(void)
{if(check_end() == 1){printf("大端\n");}else{printf("小端\n");}short shortvalue = 0x1234; if(print_all_byte((void *)&shortvalue, sizeof(shortvalue)) != -1){printf("print SHORT success!\n\n"); }int intvalue = 0x12345678; if(print_all_byte((void *)&intvalue, sizeof(intvalue)) != -1){printf("print INT success!\n\n"); }long longvalue = 0x87654321; if(print_all_byte((void *)&longvalue, sizeof(longvalue)) != -1){printf("print LONG success!\n\n"); }float floatvalue = 0.12345678; if(print_all_byte((void *)&floatvalue, sizeof(floatvalue)) != -1){printf("printf FLOAT success!\n\n"); }double doublevalue = 0.12345678; if(print_all_byte((void *)&doublevalue, sizeof(doublevalue)) != -1){printf("printf DOUBLE success!\n\n"); }int array[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 1234}; if(print_all_byte((void *)array, sizeof(array)) != -1){printf("printf ARRAY success!\n\n"); }return EXIT_SUCCESS;
}

打印变量的的每一个位


算法分析


前面通过char我们可以读取到变量的每个字节,我们进一步拓展,读取每一个字节后,再取出其对应的每一位,即可按照二进制的方式输出每个位。
读取每一位的操作,即判断某一位是1还是0,可以采用位运算完成,具体操作如下。

int isset(char data, int bit)
{ data >>= bit;if(data & 1 == 0) {return 0; }else{return 1; }
}

所以我们对上面的算法进行拓展,先取到每一个byte,然后再读取该byte的每一个bit。

int print_bit(char *addr, int size)
{unsigned char *ptr = (unsigned char *)addr;int print_bytes = 0;if(ptr == NULL){return -1; }for(print_bytes = 0;print_bytes < size;print_bytes++, ptr++){for(int print_bits = 7;print_bits >= 0;print_bits--){printf("%d", ((*ptr >> print_bits) & 1));}}printf("\n"); return print_bytes;
}

示例程序


#include <stdio.h>
#include <stdlib.h>//#define DEBUG
int isset(char data, int bit)
{ data >>= bit;if(data & 1 == 0) {return 0; }else{return 1; }
}/*
addr  -=> 待打印的变量的首地址
size  -=>·待打印的变量的大小
return 成功返回打印的字节数
*/
int print_bit(char *addr, int size)
{unsigned char *ptr = (unsigned char *)addr;int print_bytes = 0;if(ptr == NULL){return -1; }for(print_bytes = 0;print_bytes < size;print_bytes++, ptr++){
#ifdef DEBUGprintf("byte %d, data = %02x -=>", print_bytes, *ptr);
#endiffor(int print_bits = 7;print_bits >= 0;print_bits--){printf("%d", ((*ptr >> print_bits) & 1));}
#ifdef DEBUGprintf("\n");
#endif}printf("\n");
}int main(void)
{/*short shortvalue = 0x1234; if(print_bit((char *)&shortvalue, sizeof(shortvalue)) != -1){printf("print SHORT success!\n\n"); }*/int intvalue = 0x12345678;if(print_bit((char *)&intvalue, sizeof(intvalue)) != -1){printf("print INT success!\n\n"); }long longvalue = 0x87654321; if(print_bit((char *)&longvalue, sizeof(longvalue)) != -1){printf("print LONG success!\n\n"); }float floatvalue = 0.12345678; if(print_bit((char *)&floatvalue, sizeof(floatvalue)) != -1){printf("printf FLOAT success!\n\n"); }double doublevalue = 0.12345678; if(print_bit((char *)&doublevalue, sizeof(doublevalue)) != -1){printf("printf DOUBLE success!\n\n"); }int array[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 1234}; if(print_bit((char *)array, sizeof(array)) != -1){printf("printf ARRAY success!\n\n"); }return EXIT_SUCCESS;
}

深入理解计算机系统-之-数值存储(二)--C程序打印变量的每一字节或者位相关推荐

  1. 深入理解计算机系统-之-数值存储(六)--以不同的方式窥视内存

    浮点数写,整数读 好了知道了浮点数的存储方式,那么我们的问题来了,如果我们定义了一个浮点数,那么如果以整数的格式去读取它,会发生什么奇妙的现象 代码示例 我们对上一篇文章中修改main函数为如下形式 ...

  2. 深入理解计算机系统——知识总结(二)

    第 7 章 7.1 编译器驱动程序 7.2 静态链接 7.3 目标文件 7.4 可重定位目标文件 7.5 符号和符号表 7.6 符号解析 7.7 重定位 7.8 可执行目标文件 7.9 加载可执行目标 ...

  3. 读书笔记——《深入理解计算机系统》第三章_程序的机器级表示(一)

    前言:已经大四,没有去找工作,选择了保研,之所以这样选择,有三个原因,一.刚进校时,听说保研都是牛人才能行的事,所以一心努力保研:二.2008年开始,经济危机比较严重,工作不好找,虽然软件专业要找一份 ...

  4. 深入理解计算机系统_第三章_程序的机器级表示

    深入,并且广泛-沉默犀牛 文章目录 文章导读 历史观点 程序编码 机器级代码 代码示例 关于格式的注解 数据格式 访问信息 操作数指示符 数据传送指令 数据传送示例 压入和弹出栈数据 算术和逻辑操作 ...

  5. 《深入理解计算机系统》学习心得二:关于show-bytes的 学习

    此段代码,使用强制类型转换来访问和打印不同程序对象的字节表示.show-bytes打印出每个以十六进制表示的字节. /* show-bytes - prints byte representation ...

  6. 《深入理解计算机系统》读书笔记二:内存,高速缓存存储器

    主存:是一个临时的存储设备.从物理上来说,主存是一组动态随机存取存储器(DRAM)芯片组成. 从逻辑上来说,存储器是一个线性的字节数组,每个字节都有其唯一的地址(数组索引),这些地址是从零开始的. 高 ...

  7. 深入理解计算机系统(v3) 第三章、程序的机器级表示(Linux)

    程序调试:gcc -Og -o p p1.c p2.c 反汇编 objdump -d p 寄存器 函数参数第1到第6个参数:%rdi %rsi %rdx %rcx %r8 %r9 返回值 %rax 栈 ...

  8. 老赵书托(3):深入理解计算机系统

    这次我要推荐的是<Computer Systems: A Programmer's Perspective>(下文简称CSAPP),在国内可以买到其影印版.它也已经被翻译成为中文,即中国电 ...

  9. Arduino UNO + DS1302利用31字节静态RAM存储数据并串口打印

    Arduino UNO + DS1302利用31字节静态RAM存储数据并串口打印 DS1302中的31字节的非易失性静态RAM.可以用来临时保存一些重要数据. DS1302模块 DS1302简介 DS ...

最新文章

  1. GBDT算法原理及附有源码实现的 转
  2. Winform混合式开发框架的特点总结
  3. TypeScript constructor signature 类型的变量赋值方式
  4. 程序员真是一门苦差事!
  5. oracle procedure可以执行非常复杂的语句吗,oracle-存储过程(procedure)
  6. 中国上市公司2001-2020年历史股票数据下载(获得方式见网页 http://yanzw.cn )
  7. 网络安全浏览器工作原理
  8. php亲戚称谓计算源码,亲戚称呼(亲戚关系计算器在线)
  9. bzoj3717 [PA2014]Pakowanie(状压dp+贪心)
  10. MySQL的性能分析关键字,explain,及其返回值代表的意思
  11. 什么是胖客户端和瘦客户端?什么是哑终端?
  12. js中math常用使用方法
  13. 更改MyEclipse/Eclipse的工作空间名字(workspace)
  14. 【Opencv项目实战】背景替换:动态背景移除与替换(cvzone+MediaPipe)
  15. JAVA图片裁剪工具类
  16. Latex 中文简历 过程(更新Miktex和 修改utf字体)
  17. .Net混淆工具和反混淆工具
  18. 收藏!最全的可视化学入门算法教程(Python实现)
  19. Error - 52 with clEnqueueNDRangeKernel
  20. 低配置高自由度游戏_高/低游戏

热门文章

  1. networkx, 网络节点多个属性
  2. 内网穿透妙用——内网转公网nat123
  3. MAE TransMix
  4. 20220425二次型复习
  5. 使用TensorRt搭建自己的模型
  6. m4s格式转换mp3_M4A格式怎么转换成MP3
  7. 快速批量把jpg转换成pdf的方法
  8. 软件测试真的也干不到35岁吗?我还处在水深火热的测试岗...
  9. 【工业大数据】工业大数据:构建制造型企业新型能力
  10. 论文实证分析怎么写?