c格式化输出

格式化输出考察了不仅考察各种数据类型的转换以及你对内存的理解

首先,要很清楚各个不同数据类型的大小,这个做面向对象的基础

#include <stdio.h>

printf("size of int:\t\t[%d]\n", sizeof(int));
printf("size of long:\t\t[%d]\n", sizeof(long));
printf("size of long long:\t[%d]\n", sizeof(long long));
printf("size of float:\t\t[%d]\n", sizeof(float));
printf("size of double:\t\t[%d]\n", sizeof(double));

//size of int:            [4]
//size of long:           [8]
//size of long long:      [8]
//size of float:          [4]
//size of double:         [8]

 

首先考虑两类

一类是int,另一类是ascii

int的数据大小是4个bytes,最大可以表示7f ff ff ff ,最小80 00 00 00

int a = 0x7FFFFFFF;
printf("MAX %04x\n",a); //7fffffff
printf("MAX %d\n",a); //2147483647


a = 0x80000000;
printf("MIN %04x\n",a); //80000000
printf("MIN %d\n",a); //-2147483648

而一个char只占1个byte。

这里说一下格式化输出的符号

%d 以10进制方式输出

%c 以ascii方式输出

%x 以16进制方式(a/b/c/d/e/f 小写)输出, %X 以16进制方式(A/B/C/D/E/F 大写)输出

%04x 以16进制输出,指定输出长度4位,左边不够用0补而不是空白符

printf输出时,为了便于阅读,会进一步转换,[1]以ascii方式输出到显示屏幕。比如说:int 8,在内存中就是00 00 00 08,而最终输出到屏幕是一个8(如果用%d输出),如果用16进制输出,则屏幕上是00 00 00 08,[2]即会把内存内容用有限的ascii码显示出来。10进制就是数字0-9,16进制就是0-9A-B。[3](这里的输出顺序并不一定就是内存内容的顺序,需要考虑大小端的问题。)

所以,最直观看内存内容的方式,是以16进制和相应的sizeof(type)大小输出看到底是什么。比如,如果要看一个int的内存内容是什么,那么使用%04x输出。因为2进制和16进制转换容易且直观,即8位的2进制可以转为2位的16进制,2位的16进制就是一个byte。

相比而言,其他进制输出就不是很容易看出2进制的内存内容

大小端解释

什么是大小端?比如8这个int类型,可以看成是00 00 00 08,高31位是0,低1位是8。一个int使用4个bytes,我们分别看每个字节会发现,int的第一个byte的位置上的内存内容是8,第二个到第四个是0,也就是低地址的内存放的是8,高地址内存放的是0。这样的存放模式就是小端模式。数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中

int t =37;
char * pa = (char*)(&t);
printf("[%d] [%d] [%d] [%d]\n", pa[0], pa[1], pa[2], pa[3]);
printf("[%08x] [%08x] [%08x] [%08x]\n", pa, pa+1, pa+2, pa+3);

// result
// [37] [0] [0] [0]
// [cc354bdc] [cc354bdd] [cc354bde] [00000000cc354bdf]


int t1 = 2621495; //对应的16进制是28 00 37
pa = (char*)(&t1);
printf("[%d] [%d] [%d] [%d]\n", pa[0], pa[1], pa[2], pa[3]);

// result
// [55] [0] [40] [0](10进制输出),转为16进制为[37] [00] [28] [00]

long t2 = 56076300985344; //对应的16进制是33 00 48 00 24 00
pa = (char*)(&t2);
printf("[%d] [%d] [%d] [%d] [%d] [%d] [%d] [%d]\n", pa[0], pa[1], pa[2], pa[3], pa[4], pa[5], pa[6], pa[7]);

// result
// [0] [36] [0] [72] [0] [51] [0] [0] 转为16进制为[00] [24] [00] [48] [00] [33] [00] [00]

 

现在要考虑char如何转为int和int如何转为char,进一步地,就是单字节和多字节之间的转换。首先介绍一下snprintf这个函数。snprintf是sprintf的边界检查版本,具体可以百度


char b[9];
snprintf(b, sizeof(b), "%d", 0x7FFFFFFF); //对应10进制2147483647
int i = 0;
for(i = 0; i< 9; i++)
    printf("%d [%c]  ", i, b[i]);

printf("\n");

for(i = 0; i< 9; i++)
    printf("%d [%02x]  ", i, b[i]);

printf("\n");

// result
// 0 [2]  1 [1]  2 [4]  3 [7]  4 [4]  5 [8]  6 [3]  7 [6]  8 []
// 0 [32]  1 [31]  2 [34]  3 [37]  4 [34]  5 [38]  6 [33]  7 [36]  8 [00]

这里涉及到上文的[2],以及[1]。这里将int转成ascii保存进内存中。事实上这个snprintf函数会将int的每一位升格,保存到一位内存中,并且以ascii方式保存。

当有一片内存,如果想取某几位做与或非,或者想查看某几个内存内容,那么根据需求,可以取2个bytes short,4个bytes int,8个bytes long。但是要注意一下大小端。

int s = *(int*)b;
printf("%d, %04x", s, s);

// result
// 926167346, 37343132

内存位置内容,从左到右,内存地址由低到高

32 31 34 37

对应的int,小端模式,16进制,对应10进制为926167346

37343132

如果需要取int s的低8位,指的是内存地址的低8位

b & 0x000000FF

因为数据位低代表内存位低

其实说了半天,就是当使用不同的数据类型,解读内存的方式不同!而难点在于使用什么规则取解读,,,,

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章