C printf() 详解——printf('%08x',number); 程序员面试宝典中的一个错误 char * b=(char *)&a
来源:互联网 发布:淘宝严重违规扣12分 编辑:程序博客网 时间:2024/05/16 13:54
本文转自:http://www.cppblog.com/wuzimian/archive/2012/05/23/175925.aspx
1 #include<iostream>
2 using namespace std;
3 int main()
4 {
5 unsigned int a = 0xFFFFFFF7;
6 unsigned char i = (unsigned char)a;
7 char* b = (char*)&a;
8
9 printf("%08x, %08x\n", i, *b);
10 }
程序结果输出 :fffffff7,《宝典》中解释为2 using namespace std;
3 int main()
4 {
5 unsigned int a = 0xFFFFFFF7;
6 unsigned char i = (unsigned char)a;
7 char* b = (char*)&a;
8
9 printf("%08x, %08x\n", i, *b);
10 }
1 unsigned int* p = &a; // p中的内容是的地址,即p指向a
2 char* b = (char*)p; // 此处的强制转换只是使b也指向a而已
3 // 这里是char类型的指针转换,而不是char类型的转换,影响的只是指针的寻址
《宝典》认为最终b的指向和&a一样,所以程序输出就是&a指向的:fffffff7,这个解释显然是不对的,如果我们把a的值改为0x123456f7,程序也会输出fffffff7,2 char* b = (char*)p; // 此处的强制转换只是使b也指向a而已
3 // 这里是char类型的指针转换,而不是char类型的转换,影响的只是指针的寻址
而按照《宝典》的说法,应该输出123456f7才对。
正确的解释是怎样的呢?
首先我们要有这么一个认识:在X86系列的机器中,数据的存储是“小端存储”,小端存储的意思就是,对于一个跨多个字节的数据,其低位存放在低地址单元,其高位放在高
地址单元。比如一个 int 型的数据ox12345678,假如存放在0x00000000,0x00000001,0x00000002,0x00000003这四个内存单元中,那么ox00000000中放的是
低位的ox78,而ox00000003中放的是高位的0x12,以此类推。
有了以上的认识,我们可以继续分析上面的程序为什么输出fffffff7:
char* b = (char*)&a;这句话到底干了什么事呢?其实说来也简单,&a可以认为是个指向 unsigned int类型数据的指针对吧,(char *)&a则把&a强制转换成 char *类型
的指针,并且这个时候发生了截断!截断后,指针b只指向oxf7这个数据(为什么b指向最低位的oxf7而不是最高位的oxff?想想上面刚刚讲过的"小端存储"吧,低地址单元存
放低位数据,),又由于指针b是 char *型的,属于有符号数,所以有符号数0xf7在printf()的作用下输出fffffff7( 这个过程中其实发生了参数类型提升default argument
promotions),因为我对C语言不是很了解,所以看这里,
的指针,并且这个时候发生了截断!截断后,指针b只指向oxf7这个数据(为什么b指向最低位的oxf7而不是最高位的oxff?想想上面刚刚讲过的"小端存储"吧,低地址单元存
放低位数据,),又由于指针b是 char *型的,属于有符号数,所以有符号数0xf7在printf()的作用下输出fffffff7( 这个过程中其实发生了参数类型提升default argument
promotions),因为我对C语言不是很了解,所以看这里,
http://www.spongeliu.com/%E8%AF%AD%E8%A8%80%E5%AD%A6%E4%B9%A0/clanguage/ctypetransfer/
讲的比较清楚了。参考:
http://blog.csdn.net/race604/article/details/6725475
或者我们可以通过汇编代码更直观的看内部的情况:
或者我们可以通过汇编代码更直观的看内部的情况:
int main()
{
01321380 push ebp
01321381 mov ebp,esp
01321383 sub esp,0E4h
01321389 push ebx
0132138A push esi
0132138B push edi
0132138C lea edi,[ebp-0E4h]
01321392 mov ecx,39h
01321397 mov eax,0CCCCCCCCh
0132139C rep stos dword ptr es:[edi]
unsigned int a = 0xFFFFFF65;
0132139E mov dword ptr [a],0FFFFFFF7h
unsigned char i = (unsigned char)a;
013213A5 mov al,byte ptr [a]
013213A8 mov byte ptr [i],al
char* b = (char*)&a;
013213AB lea eax,[a] //取a的地址:0x0018FD70
013213AE mov dword ptr [b],eax //指针b的值为:0x0018FD70,该位置放着0xF7;
printf("%08x, %08x\n", i, *b);
013213B1 mov eax,dword ptr [b] //把b的值,也就是0x0018FD70放到EAX中;
013213B4 movsx ecx,byte ptr [eax] //这句话最关键,byte ptr [eax]就是把0xF7取出来,注意命令是byte ptr哦。然后movsx指令是按符号扩展,放到ecx中,按符号扩展其实就是将char扩展成int,然后printf中格式说明的‘x’则说明将这个int按16进制输出,也就是fffffff7了,而如果将‘x’变成‘d’,按整数输出,那么程序就会输出-9
013213B7 mov esi,esp //上一句的byte ptr 就反映了我们上面说的 char* b = (char*)&a 截取的问题
013213B9 push ecx
013213BA movzx edx,byte ptr [i] //注意因为i是unsigned char(无符号) ,所以按0扩展成unsigned int
013213BE push edx
013213BF push offset string "%08x, %08x\n" (1325830h)
013213C4 call dword ptr [__imp__printf (13282B0h)]
013213CA add esp,0Ch
013213CD cmp esi,esp
013213CF call @ILT+295(__RTC_CheckEsp) (132112Ch)
}
{
01321380 push ebp
01321381 mov ebp,esp
01321383 sub esp,0E4h
01321389 push ebx
0132138A push esi
0132138B push edi
0132138C lea edi,[ebp-0E4h]
01321392 mov ecx,39h
01321397 mov eax,0CCCCCCCCh
0132139C rep stos dword ptr es:[edi]
unsigned int a = 0xFFFFFF65;
0132139E mov dword ptr [a],0FFFFFFF7h
unsigned char i = (unsigned char)a;
013213A5 mov al,byte ptr [a]
013213A8 mov byte ptr [i],al
char* b = (char*)&a;
013213AB lea eax,[a] //取a的地址:0x0018FD70
013213AE mov dword ptr [b],eax //指针b的值为:0x0018FD70,该位置放着0xF7;
printf("%08x, %08x\n", i, *b);
013213B1 mov eax,dword ptr [b] //把b的值,也就是0x0018FD70放到EAX中;
013213B4 movsx ecx,byte ptr [eax] //这句话最关键,byte ptr [eax]就是把0xF7取出来,注意命令是byte ptr哦。然后movsx指令是按符号扩展,放到ecx中,按符号扩展其实就是将char扩展成int,然后printf中格式说明的‘x’则说明将这个int按16进制输出,也就是fffffff7了,而如果将‘x’变成‘d’,按整数输出,那么程序就会输出-9
013213B7 mov esi,esp //上一句的byte ptr 就反映了我们上面说的 char* b = (char*)&a 截取的问题
013213B9 push ecx
013213BA movzx edx,byte ptr [i] //注意因为i是unsigned char(无符号) ,所以按0扩展成unsigned int
013213BE push edx
013213BF push offset string "%08x, %08x\n" (1325830h)
013213C4 call dword ptr [__imp__printf (13282B0h)]
013213CA add esp,0Ch
013213CD cmp esi,esp
013213CF call @ILT+295(__RTC_CheckEsp) (132112Ch)
}
附上:
C printf() 详解——printf('%08x',number);
2012-04-03 15:00:01| 分类: C/C++|字号 订阅
0 0
- C printf() 详解——printf('%08x',number); 程序员面试宝典中的一个错误 char * b=(char *)&a
- C printf() 详解——printf('%08x',number); 程序员面试宝典中的一个错误 char * b=(char *)&a
- C printf() 详解——printf('%08x',number); 程序员面试宝典中的一个错误 char * b=(char *)&a
- C printf() 详解——printf('%08x',number); 程序员面试宝典中的一个错误 char * b=(char *)&a
- C printf() 详解——printf('%08x',number); 程序员面试宝典中的一个错误 char * b=(char *)&a
- 程序员面试宝典中的一个错误 char * b=(char *)&a
- 程序员面试宝典中的一个错误 char * b=(char *)&a
- 程序员面试宝典中的一个错误 char * b=(char *)&a
- 转:C printf() 详解——printf('%08x',number);
- C printf() 详解——printf('%08x',number);
- C printf() 详解——printf('%08x',number);
- C printf()详解---printf("%08x",number)
- C printf()详解---printf("%08x",number)
- char, char*,scanf,printf
- printf('%08x',number)
- char c=128;printf("%d",c);问题
- (转) char c=128;printf("%d",c);问题
- char*& ,printf("a%sb"):aa%sbb?
- iOS 基础题
- 20160205交易记录
- BZOJ 1305: [CQOI2009]dance跳舞
- 【翻译自mos文章】在windows平台上怎么启用Oracle database 企业版的partition?
- VS2013 更改MFC标题栏图标和生成的执行文件图标
- C printf() 详解——printf('%08x',number); 程序员面试宝典中的一个错误 char * b=(char *)&a
- eclipse 交叉编译unresolved inclusion:<stdio.h>问题
- ADO.NET之存储图片路径
- 怎么读Man Page和BNF
- abstract 抽象类
- BZOJ 2096: [Poi2010]Pilots
- 2015年终总结
- 建筑图纸符号大全
- NYOJ 题目68 三点顺序