研究问题
- Printf,print,println
- Sprintf与Sprintf_s
- 地址打印%p与%#x区别??
要点:
- Printf是C语言中格式化输出;print是标准输出,但是不换行;println和print差不多,就是最后会换行:println(“test”)相当于print(“test\n”)。
- %p指打印地址,没有格式的规定。
- %x指以十六进制形式打印。
- \t指后退一个制表符,相当于按了一个Tab键(8个空格键),在第8列打印或输出。
int a[10] = {1,2,3,4,5,6,7,8,9,10};
printf("&a[0]=%p\ta=%p\t&a=%p\n", &a[0],a,&a);
输出结果:
第一个\t是从a[0]地址0046FE18中的“4”开始后退一个制表符,第二个\t是从“8”开始后退一个制表符;
原因:第二个表示a所存储的内存地址,这块内存存在堆上
第三个表示a本身的内存地址,这块内存在栈上int sprintf_s(char *buffer,size_t sizeOfBuffer,const char *format [,argument] …);
如:
sprintf_s(filename,"%s %s %s %s",path1,filepath,path3,path4);
%p对地址打印,以大写字母输出,如:0028FEF4
%#x对地址打印,以小写字母输出,如:0x28fef3
疑难杂症
为什么内存地址总是以0x00开头?
在32位系统中,数据总线宽度为32,每次能读取4字节,地址总线宽度为32,因此最大的寻址空间为2^32=4GB,但是最低2位A[0],A[1]是不用于寻址,A[2-31]才能存储器相连,因此只能访问4的倍数地址空间,但是总的寻址空间还是2^30*字长=4GB,因此在内存中所有存放的基本类型数据的首地址的最低两位都是0,除结构体中的成员变量。最低2位A[0],A[1]是不用于寻址,是最低2位么?在内存中,一般都是0x00开头,应该是最高两位吧?
是最低两位, 内存地址没有要求以 0x00 开头, 是你的程序没用到那么多, 或者是你的操作系统设置并没要让程序可以使用全部 4G 空间.
Unix (like)中(不知道windows是怎么实现的),每个进程都会分配到4G的虚拟内存空间,用于存储进程中的数据(和俗称的虚拟内存不太相同)。然后这4g中的前3g是用户数据(最后1g是系统数据),这3g中从两端向中间分成了各种段地址(如堆,栈,环境变量,BSS,静态常量等),堆和栈正巧处于这两端的末尾,这样设计的原因是为了有足够的空间来加载库文件,和变量的内存,或其他紧急需要分配的内存,以不致造成内存不够,重新找地方分内存,导致内存混乱如果是最低2位,倒是是4的倍数,但是实际上有0x00ff4233这样的char变量地址,并不被4整除?
不被 4 整除的数据, 从可以整除的位置的地址来读, 一次读取 4 个字节, 然后在 CPU 内只使用需要的那个字节. 所以 CPU 对内存的寻址都是可以被 4 整除的, 但是并不要求程序里面的地址都必须被 4 整除.因此在内存中所有存放的基本类型数据的首地址的最低两位都是0,是都是0么?应该是地址的最高位吧?
解析:- 是最低两位, 内存地址没有要求以 0x00 开头, 是你的程序没用到那么多, 或者是你的操作系统设置并没要让程序可以使用全部 4G 空间.
Unix (like)中(不知道windows是怎么实现的),每个进程都会分配到4G的虚拟内存空间,用于存储进程中的数据(和俗称的虚拟内存不太相同)。然后这4g中的前3g是用户数据(最后1g是系统数据),这3g中从两端向中间分成了各种段地址(如堆,栈,环境变量,BSS,静态常量等),堆和栈正巧处于这两端的末尾,这样设计的原因是为了有足够的空间来加载库文件,和变量的内存,或其他紧急需要分配的内存,以不致造成内存不够,重新找地方分内存,导致内存混乱。 - 不被 4 整除的数据, 从可以整除的位置的地址来读, 一次读取 4 个字节, 然后在 CPU 内只使用需要的那个字节. 所以 CPU 对内存的寻址都是可以被 4 整除的, 但是并不要求程序里面的地址都必须被 4 整除.
- 地址在内存中的是低位为还是高位和系统的大小端有关. 但是不管如何, 内存中的地址可以是任意值, 并不要求高两位或低两位为 0. 只是 CPU 去寻址内存的时候总是 4 个字节的读, 所以低两位的地址被 CPU 内部处理了.
- 是最低两位, 内存地址没有要求以 0x00 开头, 是你的程序没用到那么多, 或者是你的操作系统设置并没要让程序可以使用全部 4G 空间.