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,《宝典》中解释为
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,
而按照《宝典》的说法,应该输出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语言不是很了解,所以看这里,
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)
}
附上:
C printf() 详解——printf('%08x',number);
2012-04-03 15:00:01| 分类: C/C++|字号 订阅
printf()函数是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息。在编写程序时经常会用到此函数。函数的原型为:
int printf(const char *format, ...);
函数返回值为整型。若成功则返回输出的字符数,输出出错则返回负值。
printf()函数的调用格式为:
printf("<格式化字符串>", <参量表>);
其中格式化字符串包括两部分内容: 一部分是正常字符, 这些字符将按原样输出; 另一部分是格式化规定字符, 以"%"开始, 后跟一个或几个规定字符,用来确定输出内容格式。
参量表是需要输出的一系列参数, 其个数必须与格式化字符串所说明的输出参数个数一样多, 各参数之间用","分开, 且顺序一一对应, 否则将会出现意想不到的错误。
1. 格式化规定符
Turbo C2.0提供的格式化规定符如下:
a 符号 作用
%d 十进制有符号整数
%u 十进制无符号整数
%f 浮点数
%s 字符串
%c 单个字符
%p 指针的值
%e 指数形式的浮点数
%x, %X 无符号以十六进制表示的整数
%o 无符号以八进制表示的整数
%g 自动选择合适的表示法
说明:
(1). 可以在"%"和字母之间插进数字表示最大场宽。
例如: %3d 表示输出3位整型数, 不够3位右对齐。
%9.2f 表示输出场宽为9的浮点数, 其中小数位为2, 整数位为6,
小数点占一位, 不够9位右对齐。
%8s 表示输出8个字符的字符串, 不够8个字符右对齐。
如果字符串的长度、或整型数位数超过说明的场宽, 将按其实际长度输出。
但对浮点数, 若整数部分位数超过了说明的整数位宽度, 将按实际整数位输出;
若小数部分位数超过了说明的小数位宽度, 则按说明的宽度以四舍五入输出。
另外, 若想在输出值前加一些0, 就应在场宽项前加个0。 (即不够场宽的用0补足)
例如: %04d 表示在输出一个小于4位的数值时, 将在前面补0使其总宽度为4位。
如果用浮点数表示字符或整型量的输出格式, 小数点后的数字代表最大宽度, 小数点前的数字代表最小宽度。
例如: %6.9s 表示显示一个长度不小于6且不大于9的字符串。若大于9, 则第9个字符以后的内容将被删除。
(2). 可以在"%"和字母之间加小写字母l, 表示输出的是长型数。
例如: %ld 表示输出long整数
%lf 表示输出double浮点数
(3). 可以控制输出左对齐或右对齐, 即在"%"和字母之间加入一个"-" 号可说明输出为左对齐, 否则为右对齐。
例如: %-7d 表示输出7位整数左对齐
%-10s 表示输出10个字符左对齐
2. 一些特殊规定字符
b 字符 作用
\n 换行
\f 清屏并换页
\r 回车
\t Tab符
\xhh 表示一个ASCII码用16进表示,
其中hh是1到2个16进制数
由本节所学的printf()函数, 并结合上一节学习的数据类型, 编制下面的程序, 以加深对Turbo C2.0数据类型的了解。
printf()和sprintf()在php中的应用
<?php
printf("$%01.2f", 43.2); // 运行结果:$43.20
echo "
";
printf("%d bottles of beer on %s", 100, "the wall");
echo "
";
//运行结果:100 bottles of beer on the wall
printf("%15s", "some text"); //运行结果:some text
?>
<?php
echo "
";
printf("The %2\$s likes to %1\$s", 111, dog);
echo "
";
//运行结果: The dog likes to bark
printf("The %1\$s says: %2\$s, %2\$s.", "dog", "bark");
//运行结果:The dog says: bark, bark.
?>
<?php
echo "
";
$var1 = 68.75;
$var2 = 54.35;
$var3 = $var1 + $var2;
echo $var3;
echo "
";
// 变量 $var3 值为 "123.1";
$formatted = sprintf ("%01.2f", $var3);
echo "
";
echo $formatted;
// 变量$var3 值为 "123.10"
?>
<?php
echo "
";
$money = 1.4;
$formatted = sprintf ("%-01.2f", $money);
echo $formatted;
?>