诡异的转型陷阱.......

redleaves 2010-06-07 11:50:49
#include <stdio.h>
int main() {
char buf[4] = {(char)0xCC,(char)0xCC,(char)0xCC,(char)0xCC};
int cccc = 0xCCCCCCCC;
printf( "1.0x%08llx\n", reinterpret_cast<unsigned long long>(((void**)buf)[0]));
printf( "2.0x%08llx\n", reinterpret_cast<unsigned long long>((void*)0xCCCCCCCC));
printf( "3.0x%08llx\n", static_cast<unsigned long long>(0xCCCCCCCC));
printf( "4.0x%08llx\n", static_cast<unsigned long long>(-1));
printf( "5.0x%08llx\n", reinterpret_cast<unsigned long long>((void*)-1));
printf( "6.0x%08llx\n", static_cast<unsigned long long>(cccc));
printf( "7.0x%08llx\n", reinterpret_cast<unsigned long long>((void*)cccc));
printf( "8.0x%08llx\n", reinterpret_cast<unsigned long long>(((void**)&cccc)[0]) );
return 0;
}
估计没几个人能说出正确的结果....
其实这段代码根本没有正确的结果.因为标准里没有规定具体的实现.不同的编译器编译出来的结果也是五花八门.
虽然转型是不被提倡的.但有的时候确实无法避免.所以很有必要了解具体的编译行为.
对于指针和整数之间的转型,标准里只明确必须达到 指针转整数再转指针 或 整数转指针再转整数,结果不变.这种效果.(有个前提,就是尽量保证和物理机器的地址的一致性.不要造成混淆)
于是,对于指针和整型的转换就有了几种不同的做法:
1.按unsigned转换.
2.按signed转换.
3.按目标类型转换.
对于不用做提升操作的转换,这些方式都差不多.做对于要做类型提升操作的转换.就有可能出岔子了.
VC的编译结果如下:
1.0xffffffffcccccccc
2.0xcccccccc
3.0xcccccccc
4.0xffffffffffffffff
5.0xffffffff
6.0xffffffffcccccccc
7.0xffffffffcccccccc
8.0xffffffffcccccccc
可以看到,正常情况下,VC对指针的提升是按signed类型操作的.但请注意第2项.当把一个无符号常量强制转为指针再进行提升的时候,就变成按unsigned类型操作了...相同结果的还有第5项.这里VC竟然区别对待常量和变量...

同样的代码,gcc的结果是:
1.0xffffffffcccccccc
2.0xffffffffcccccccc
3.0xcccccccc
4.0xffffffffffffffff
5.0xffffffffffffffff
6.0xffffffffcccccccc
7.0xffffffffcccccccc
8.0xffffffffcccccccc
GCC的结果就具有很好的一致性.只要是指针都是按signed类型进行提升.

而icl则相反:
1.0xcccccccc
2.0xcccccccc
3.0xcccccccc
4.0xffffffffffffffff
5.0xffffffff
6.0xffffffffcccccccc
7.0xcccccccc
8.0xcccccccc
只要是指针都是按unsigned类型进行提升

其它我还测试了bcc,dmc,owcc,mwcc.
其中dmc和icl的结果一致.
bcc和owcc的结果一致,都是和VC有点类似的方式.
mwcc则是按自己的方式进行操作.

总的来说,gcc,icl,dmc的转型都具有很好的一致性.虽然他们结果不同,但不会像vc那样还区别对待常量.

虽然这个东西不是标准的内容,但因为转型没法完全避免.了解清楚总比错的莫名其妙好...
和大家共勉了...
...全文
210 24 打赏 收藏 举报
写回复
24 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
赵4老师 2010-06-17
[Quote=引用 16 楼 cs_yagami 的回复:]
引用 14 楼 zhao4zhong1 的回复:

VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!

怎麼覺得這幾句話出現了好幾次..囧[/Quote]
敢問有幾個人照做了?
  • 打赏
  • 举报
回复
赵4老师 2010-06-16
[Quote=引用 22 楼 milkylove 的回复:]
引用 16 楼 cs_yagami 的回复:

引用 14 楼 zhao4zhong1 的回复:

VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东……
[/Quote]
另外再悄悄的告诉你 看汇编代码是无法区分signed 和 unsigned的。

那请问milkylove:汇编指令JA和JG的区别?
  • 打赏
  • 举报
回复
失落的凡凡 2010-06-09
[Quote=引用 16 楼 cs_yagami 的回复:]

引用 14 楼 zhao4zhong1 的回复:

VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!

怎麼覺得這幾句話出現了好幾次..囧
[/Quote]

悄悄的告诉你 这是位机器人大叔, 只会说三句话

另外再悄悄的告诉你 看汇编代码是无法区分signed 和 unsigned的。
  • 打赏
  • 举报
回复
annhoo 2010-06-09
谢谢,分享。真是难为你了!呵呵
  • 打赏
  • 举报
回复
scudc 2010-06-08
我的vc6还要编译错误。。。。
  • 打赏
  • 举报
回复
ForestDB 2010-06-08
[Quote=引用 15 楼 zhao4zhong1 的回复:]
不要迷信书、考题、老师;
要迷信CPU、编译器、调试器。
[/Quote]
这个可以顶。
支持LZ。
  • 打赏
  • 举报
回复
shuai13869896140 2010-06-08
LZ牛人,真是有心了```
  • 打赏
  • 举报
回复
yunyun1886358 2010-06-08
不懂,unsigned long long。
顺便问一下,两个long是什么意思?
  • 打赏
  • 举报
回复
z569362161 2010-06-08
中科院IT工程硕士 为IT人加油
  • 打赏
  • 举报
回复
cs_yagami 2010-06-08
[Quote=引用 14 楼 zhao4zhong1 的回复:]

VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
[/Quote]
怎麼覺得這幾句話出現了好幾次..囧
  • 打赏
  • 举报
回复
赵4老师 2010-06-08
不要迷信书、考题、老师;
要迷信CPU、编译器、调试器。
  • 打赏
  • 举报
回复
赵4老师 2010-06-08
VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
  • 打赏
  • 举报
回复
azure110 2010-06-08
支持 lz
  • 打赏
  • 举报
回复
pengzhixi 2010-06-08
收藏下
  • 打赏
  • 举报
回复
AlanBruce 2010-06-08
Take It Easy
  • 打赏
  • 举报
回复
cattycat 2010-06-08
谢谢分享。
  • 打赏
  • 举报
回复
selooloo 2010-06-08
用dev printf %llx 仍然按32位打印的
  • 打赏
  • 举报
回复
z569362161 2010-06-08
[Quote=引用 4 楼 yunyun1886358 的回复:]
不懂,unsigned long long。
顺便问一下,两个long是什么意思?
[/Quote]

新语法,超长整型。但是需要编译器支持
  • 打赏
  • 举报
回复
hzy694358 2010-06-08
牛逼哄哄……
学习
  • 打赏
  • 举报
回复
saiweng198 2010-06-08
学习了,DING……
  • 打赏
  • 举报
回复
加载更多回复
相关推荐
发帖
C++ 语言
加入

6.2w+

社区成员

C++ 语言相关问题讨论,技术干货分享,前沿动态等
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
申请成为版主
帖子事件
创建了帖子
2010-06-07 11:50
社区公告
暂无公告