免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: walleeee
打印 上一主题 下一主题

不知道大家看了这个是什么心里滋味 [复制链接]

论坛徽章:
0
21 [报告]
发表于 2012-04-25 18:34 |只看该作者
  1. int main()
  2. {
  3.     const int v = 12;
  4.     int x = 0;
  5.    
  6.     x = v;
  7.     *(int*)&x = v;
  8.     *(float*)&x = v;
  9.     float k = 12;
  10.    
  11.     return 0;
  12. }
复制代码
在1,2都没做类型转换。3做了类型转换,于是v抬升为float,成为12.0f,满足ieee的规范布局,于是x被搞成了32bit应对的ieee浮点,于是x再变成整数的时候自然和真正的12整数不等

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
22 [报告]
发表于 2012-04-25 19:20 |只看该作者
walleeee 发表于 2012-04-25 18:34
在1,2都没做类型转换。3做了类型转换 ...


为什么1,2不做?3要做?  什么又叫类型转换?  没有类型又根据怎么转换?
将C看作地址、看作内容什么的都无所谓。


读写内容必定涉及内容的格式 —— 哪部分是value bits? sign bit? padding bits? 又或者哪部分是sign/exponent/fraction? —— 并按这个格式解释(读取)/构造(写入)内容。
类型就包含有这样的格式信息。
上面是基本类型,对复合类型:从何处开始直到何处是哪个field?它的读写规则又是什么(如果本身是基本类型则直接解释否则递归)?

论坛徽章:
0
23 [报告]
发表于 2012-04-25 19:27 |只看该作者
回复 22# OwnWaterloo


这里有个隐式抬升。int会自动抬到int。
1,2不做是因为1,2不需要做。

这个b规范描述得很明白,只是要真的理解该作者的深意。我相信c不会高级到哪里去。

关于内容格式,这里编译器会有浮点格式化,把文本量转换到数据量,它们在我理解不是一回事。
我后面看不懂你的意思。

“从何处开始直到何处是哪个field?它的读写规则又是什么(如果本身是基本类型则直接解释否则递归)?”

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
24 [报告]
发表于 2012-04-25 19:35 |只看该作者
回复 23# walleeee

>> 1,2不做是因为1,2不需要做。

我擦,这也行?


>> 关于内容格式,这里编译器会有浮点格式化,把文本量转换到数据量,它们在我理解不是一回事。

那换种说法。

  1. unsigned char* p = (unsigned char*)calloc(1, MAX(sizeof(int), sizeof(float) ) );
  2. p[0] = 12;
复制代码
同样一段内容[p, p + MAX(sizeof(int), sizeof(float) ) )
*(int*)p 的值是多少?
*(float*)p 的值又是多少?
依据是什么


>> 我后面看不懂你的意思

struct T; // 声明
struct T* q = (struct T*)p;
如何获取q的内容? 依据又是什么?

论坛徽章:
0
25 [报告]
发表于 2012-04-25 19:57 |只看该作者
回复 24# OwnWaterloo


    惊讶么?我觉得很正常啊

第一个和大小端有关,你p回来的地址如果是一个byte,该byte为12,假设sizeof(int)==sizeof(float)==4,那后面还有3个Byte
这个时候内存布局是:12 0 0 0
但是你转int后就带来大小端问题。
只是我测试为12,看来我是小端机器。(intel cpu)

对于第二个。这个就跟我前面说的一样,和你那个问题一样,int*到float*的强制转换只是地址的转换,但是并非内容的转换,所以之后*解出数据这个时候就遭了,得到的就并不是12.0f这种所谓预期的,而是真正预期的“非法”无效数据
所以第二个转换比第一个转换更容易出错,而且基本就是100%出错,第一个还要看是什么端机器,运气好也没问题,我经常看到第一个那种转换的开源代码。(潜在bug)

指针转换是纯数值转换,就是一个地址转换为另外一个地址,不设计其他任何操作,在真正访问数据的时候才涉及数据解析,指针的转换是没有意义的转换,所以在汇编层面根本就不存在指针的转换,所有指针都是一种指针,没有类型的概念,数据就是内存,内存考指针定位,就这么回事。到了c有了类型概念,才出现这些转换。

我写得可能不是很清晰,你仔细理解,想必能明白。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
26 [报告]
发表于 2012-04-25 20:12 |只看该作者
本帖最后由 OwnWaterloo 于 2012-04-25 20:16 编辑

回复 25# walleeee

嘿,我又没说*(int*)p就是12,又或者0x120000...什么的。更没说*(float*)p应该是12.f。
为什么你会这么想呢

没有所谓"预期"的、应该被获取出的值。那可是unsigned char*, byte指针呢。
*(int*)p, *(float*)p, 以及q, 它们所在地址的内容完全相同, 我的问题是:
*(int*)p, *(float*)p, 以及q, 它们所在地址的内容完全相同, 12只是我随便写的,不妨假设为一个合法的ieee754表示,同时也是一个合法的补码表示,我的问题是:
1. 获取它们内容的依据是什么?
2. 获取到的值相同吗?


>> 指针转换是纯数值转换,就是一个地址转换为另外一个地址,不设计其他任何操作,在真正访问数据的时候才涉及数据解析,指针的转换是没有意义的转换,所以在汇编层面根本就不存在指针的转换,所有指针都是一种指针,没有类型的概念,数据就是内存,内存考指针定位,就这么回事。到了c有了类型概念,才出现这些转换。

你自己是不是也承认了C有了类型的概念?

另外:

>> 汇编层面根本就不存在指针的转换,所有指针都是一种指针,没有类型的概念

汇编怎么的我不管;对C而言,指针有类型的概念。
而且C对指针的定义比你想象的要严: http://c-faq.com/null/machexamp.html

如果你用某几种汇编解释C,你得到的只是使用那几种汇编的平台上的C实现,而不是C语言本身。

至于这些乱七八糟的机器是否还存在,C是否应该在后续标准中不支持它们,这是另一个问题。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
27 [报告]
发表于 2012-04-25 20:41 |只看该作者
回复 25# walleeee

补一个:

  1. #include <limits.h>
  2. #include <stdlib.h>

  3. #include <iostream>
  4. #include <iomanip>
  5. #include <limits>

  6. int main(void)
  7. {
  8.       using namespace std;

  9.       typedef int constant[  CHAR_BIT==8
  10.                           && sizeof(int)==4
  11.                           && sizeof(float)==sizeof(int)
  12.                           && numeric_limits<float>::is_iec559
  13.                           ? 1: -1];
  14.       union
  15.       {
  16.             unsigned x;
  17.             unsigned char b[sizeof(int)];
  18.       } little_endian = { 1 };
  19.       unsigned char* p = (unsigned char*)malloc(4);
  20.       memcpy(p, little_endian.b[0]? "\x00\x00\xc0\x3f": "\x3f\xc0\x00\x00", 4);

  21.       cout<<hex<<*(int*)p<<endl;
  22.       cout<<*(float*)p<<endl;
  23.       free(p);
  24.       return 0;
  25. }
复制代码
内容都是[p, p+4) —— p可是unsigned char*, byte指针:
1. *(int*)p 的值应该是什么?
2. *(float*)p 的值又应该是什么? iec559是ieee754的另一种说法。
3. 都合法吗?
4. 依据是什么?

论坛徽章:
0
28 [报告]
发表于 2012-04-26 01:32 |只看该作者
回复 26# OwnWaterloo


为什么你会这么想呢

我顺带一提

获取它们内容的依据是什么

我不说反复说了我的理解么?尽管内存内容相同,但是不代表表示的数据都有意义或有效(类型)

获取到的值相同吗

内存相同,(换个词,有意义的值)不同

你自己是不是也承认了C有了类型的概念

有没有,是相对而言。我说了,指针尽管标准或者其他什么描述给了类型,但是我个人理解下来,指针可以说有类型,也可以说没有类型,比如char *p和char* p这两种写法就是一个例子,怎么理解?指针算类型还是不算类型?我之前在那个代码风格帖子里面说了,指针算类型。但是并非这种概念就是绝对的,c尽管有这些规定。指针数据有个特殊性,其大小一般都是常量,指针和整数之间的转换也体现了这个深层次意义。

C有类型,但是也没有严格类型,就像太极,你有我,我有你。

至于这些乱七八糟的机器是否还存在,C是否应该在后续标准中不支持它们,这是另一个问题

这些不重要

论坛徽章:
0
29 [报告]
发表于 2012-04-26 01:38 |只看该作者
回复 27# OwnWaterloo


1. *(int*)p 的值应该是什么?
2. *(float*)p 的值又应该是什么? iec559是ieee754的另一种说法

不该是什么。内存相等的2块。

都合法吗?

合法。只是这样做是一个不正确的形式。

依据是什么?

我一直不明白你到底要干什么,依据我也说得很明白,内存是客观的,而对内存的看法和用法是主观的,客观存在不以主观转移,这些基本的哲学你该明白,你明白这个,为什么就不明白这里的程序?

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
30 [报告]
发表于 2012-04-26 02:06 |只看该作者
C是否没有类型而只有内存地址与内存内容? 想说的我差不多说完了。

顺带关于这个:
>> 指针数据有个特殊性,其大小一般都是常量,指针和整数之间的转换也体现了这个深层次意义。
再给你个八卦读物: http://c-faq.com/ptrs/int2ptr.html


我已经摸清你的套路了,一旦你开始死犟,就可以随你犟了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP