Chinaunix
标题:
float 能作为 bool 使用?
[打印本页]
作者:
linjxwell
时间:
2015-09-24 11:13
标题:
float 能作为 bool 使用?
公司代码里看到有用 float 作为 if 语句的判断, 所以写了以下的测试程序, 结果在 vs2010 和 g++ 4.8.4 都会输出 false 那一行. 我疑问: 0.0f 的位模式和整形 0 是一样的? 还是说编译器处理了?
#include <cstdio>
int main(int argc, char* argv[])
{
float f = 0.0f;
if (f)
printf("0.0f true\n");
else
printf("0.0f false\n");
printf("===\n");
union GameValue
{
int nValue;
float fValue;
};
GameValue gv;
gv.fValue = 0.0f;
if (gv.nValue)
printf("gv.fValue==0.0f true\n");
else
printf("gv.fValue==0.0f false\n");
return 0;
}
复制代码
作者:
hellioncu
时间:
2015-09-24 11:22
部分浮点数能精确表示。
反正别这么用。
作者:
bruceteen
时间:
2015-09-24 12:12
0.0f 的位模式和整形 0 是一样的?
------ 确实可能一样,但和你的问题无关,if (f) 相当于 if( f !=0 )
给你一个示例:
#include <stdio.h>
#include <string.h>
int main( void )
{
unsigned a = 0x80000000; // 看好,这里不是0
float b;
memcpy( &b, &a, sizeof(b) );
if( b )
printf( "true\n" );
else
printf( "false\n" ); // 执行这一句
return 0;
}
复制代码
b的位模式和整型0是不一样的,但仍然执行else那句。
C标注如是说:
if( expression ) statement
The substatement is executed if the expression compares unequal to 0.
作者:
safedead
时间:
2015-09-24 16:26
回复
3#
bruceteen
你这段代码被gcc4.4.7编译成了如下汇编代码,条件判断被直接干掉了
gcc -Wall -O2 test.c -S
.file "test.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "false"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB30:
.cfi_startproc
movl $.LC0, %edi
subq $8, %rsp
.cfi_def_cfa_offset 16
call puts
xorl %edi, %edi
call exit
.cfi_endproc
.LFE30:
.size main, .-main
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-16)"
.section .note.GNU-stack,"",@progbits
复制代码
作者:
safedead
时间:
2015-09-24 16:30
回复
2#
hellioncu
同意,强烈建议不要这么用,编译器如何私下处理这种东西是难以测度的
作者:
bruceteen
时间:
2015-09-24 16:35
回复
4#
safedead
这是两回事
之所以会优化掉,是因为编译器知道if(f)必然不成立;之所以知道if(f)必然不成立,是因为f在编译期间就确定了0值。
或者这么说:
假如你用 scanf 输入 a 值 0x80000001,那么编译器就没法优化,但依然输出 false
作者:
safedead
时间:
2015-09-24 16:54
回复
6#
bruceteen
我把代码稍微改了下
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
int foo(float b)
{
if( b )
printf( "true\n" );
else
printf( "false\n" );
return 0;
}
int main(int argc, char *argv[])
{
foo(0.0f);
foo(0.1f);
exit(EXIT_SUCCESS);
}
复制代码
编译执行:
[root@sxy-lenovo ~]# gcc -Wall -O2 test.c
[root@sxy-lenovo ~]# ./a.out
false
true
很有趣是不?(虽然是恶趣味)
查看汇编代码,if那句被翻译成下面这段:
ucomiss .LC0(%rip), %xmm0
jp .L9
jne .L9
复制代码
看到这段我就震惊了,jne的含义好说,不等于,jp是啥意思?为奇数!
楼主贴的代码看来没大家想的那么简单,如果是产品代码,里面估计还有其它含义
作者:
linjxwell
时间:
2015-09-24 18:17
本帖最后由 linjxwell 于 2015-09-24 18:22 编辑
回复
7#
safedead
应该没什么神秘的含义, 主要是那个 union 的代码, 原来是
if (gv.fValue)
复制代码
后来被人改掉了, 改为
if (gv.nValue)
复制代码
并写上注释说(大意): 用 float 作 bool 是不对的
然后我就不知道为什么不行?
如果是我改的话, 我会改为
if (gv.fValue > 0.0f)
复制代码
因为代码后面是 gv.fValue 的值去乘其他的数, 所以, 这里 if 语句主要是判断不等于 0 的情况, 但是又因为用到了 union, 所以, 感觉改的不对, 而又有疑惑~
而我又没学过汇编..
作者:
safedead
时间:
2015-09-24 19:50
回复
8#
linjxwell
汇编不能用于理解C语言语法,仅仅能作为一个实现的参考
float不是简单的数据,它是有特定结构的,有兴趣的话可以去看IEEE754浮点数的资料
正因为它具有特定结构,所以不能简单的比较
在if语句中,使用float通常要用标准的浮点表达式,常见的规则之一就是不推荐用 "=="去和浮点常数比较
一个简单的10进制浮点数转化为2进制浮点数很可能变成无限循环小数从而产生误差
作者:
bruceteen
时间:
2015-09-25 10:19
回复
8#
linjxwell
作者搞错了吧
根据C标准,只要是scalar type就可以作为if的表达式,所以 if( float ) 是完完全全符合标准的,而且C标准明确说了它相当于 if( float != 0 )
反而,作者通过union存进去float,取出来int,这种行为却是未定义行为,可以google一下 类型双关(type punning) 和 严格别名(strict aliasing) 相关的内容
作者:
linjxwell
时间:
2015-09-25 12:09
回复
10#
bruceteen
谢谢你的资料提示!
但我想我没有搞错, 我们的程序中不允许出现负值的, 所以, 我改为了
if (fValue > 0.0f)
复制代码
作者:
shang2010
时间:
2015-09-25 13:49
bool是计算机最基本的数据类型,是用来表示二进制的,
什么数字字母人工智能都是bool慢慢堆起来的,float是什么??
作者:
hevake_lcj
时间:
2015-09-26 18:24
不管编译器是否支持,我们都不能这么干。
规规矩矩按语法编法,不要去挑战编译器的下限,说不定哪个编译不支持了呢?吃亏的还不是你自己。
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2