int *和float *类型的区别是什么?

4

给定以下代码片段:

int *iptr;
float *fptr;
float fval;
fval = 0.0;
fptr = &fval;
iptr = fptr;
printf("%d \n", *iptr);
fval = 1.0;
printf("%d \n", *iptr);

输出结果为:

0
1065353216

为什么第一个打印语句至少近似于与*iptr相关的值(0.0),而第二个打印语句不是呢?这与浮点数和整数在内存中的表示方式有关。

Try printf("%d", fval); - 0xF1
4
阅读有关浮点数表示的内容,然后你就会理解。 - RedX
1
一个很好的浮点数表示初学者参考资料可以在这里找到:http://floating-point-gui.de。 - Richard J. Ross III
6个回答

12
当你写下printf("%d \n", *iptr);时,你要求printfiptr指向的值解释为整数。
恰好,0float版本由int版本的相同位表示。特别地,这些位都是0
然而,任意一个浮点数,如1.0,将具有不同的位表示(由IEEE标准定义),当解释为int时将没有多少意义。
维基百科文章解释了浮点数如何以位表示。

@merlin2011:这里严格别名不是问题吗?(例如,在这里:https://dev59.com/43VD5IYBdhLWcg3wE3Ro,“基本上,如果您有一个int*和float*,它们不允许指向同一内存位置。如果您的代码不遵守此规则,则编译器的优化器很可能会破坏您的代码。” - user2793162
@dmcr_code 当然是这样的。这就是为什么我添加了自己的答案。 - ajay
1
@ajay:是的,我认为必须提到;(不幸的是)C语言有许多“恶心”的细节需要了解(我最近也接触了一些,比如这个问题,或者有符号/无符号混合等)。 - user2793162
@dmcr_code 编写安全、符合标准的 C 代码远非易事,需要认真努力。我自己也是在艰难的学习中。 - ajay
@ajay:标准合规性是我到目前为止还没有“考虑”过的事情,我通常尝试用我学到的东西(例如使用书籍)来编写代码,而不是重新发明轮子并避免一些神秘的表达方式等等。同时,我会注意像这样的陷阱。 - user2793162
@ajay,感谢您补充了自己的答案。严格别名确实是一个问题,但当我看到这个问题时,这不是我首先想到的事情。 :) - merlin2011

3

语句iptr = fptr;会引发未定义行为

因此,猜测结果没有多大意义。


为什么会出现“未定义行为”? - 0xF1
1
因为你实际上是将一个强制转换为不相关的指针类型。 - Bathsheba
@Bathsheba,您能引用标准中相关的部分来解释一下吗? - ajay
我现在在咖啡店,无法操作。但这有点像执行(int*)(void*)(float*)&fval,我们都知道这是未定义行为。 - Bathsheba

3
@merlin已经很好地、清楚地解释了您代码的输出。然而,还有更多需要补充的内容,我在这里加上。您的代码违反了严格别名规则,并调用了未定义的行为。严格别名规则意味着不同的指针类型不应该指向同一内存位置。
iptr = fptr;

iptrint * 类型,fptrfloat * 类型。这个语句将 fptr 赋值给了 iptr,它们是不同的类型,这意味着它们现在都指向了 fval。这违反了严格别名规则。这会导致未定义行为,意味着无法预测的行为。标准对实现处理这种情况没有任何要求。简而言之,应避免导致未定义行为的代码。


2

这是一种未定义的行为:iptr = fptr;。你不能将一个浮点数打印成整数,浮点数以IEEE754格式存储。

你需要尝试这个:

printf("%d", fval);

1
一个零浮点数由零组成。任何其他数字不仅是数字,而且还有指数和尾数 - 当然,它们都不只是你的数字。

1

浮点数以IEEE754格式存储,其中像1.0这样的数字的值与1有很大不同(它被偏移以允许负数和指数)。您不能将浮点数打印为整数并使结果类似于分配给浮点数的数字。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接