免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 23223 | 回复: 12
打印 上一主题 下一主题

[C++] float 能作为 bool 使用? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-09-24 11:13 |只看该作者 |倒序浏览
公司代码里看到有用 float 作为 if 语句的判断, 所以写了以下的测试程序, 结果在 vs2010 和 g++ 4.8.4 都会输出 false 那一行. 我疑问: 0.0f 的位模式和整形 0 是一样的? 还是说编译器处理了?
  1. #include <cstdio>

  2. int main(int argc, char* argv[])
  3. {
  4.         float f = 0.0f;
  5.         if (f)
  6.                 printf("0.0f true\n");
  7.         else
  8.                 printf("0.0f false\n");

  9.         printf("===\n");

  10.         union GameValue
  11.         {
  12.                 int nValue;
  13.                 float fValue;
  14.         };

  15.         GameValue gv;
  16.         gv.fValue = 0.0f;
  17.         if (gv.nValue)
  18.                 printf("gv.fValue==0.0f true\n");
  19.         else
  20.                 printf("gv.fValue==0.0f false\n");

  21.         return 0;
  22. }
复制代码

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
2 [报告]
发表于 2015-09-24 11:22 |只看该作者
部分浮点数能精确表示。
反正别这么用。

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
3 [报告]
发表于 2015-09-24 12:12 |只看该作者
0.0f 的位模式和整形 0 是一样的?
------ 确实可能一样,但和你的问题无关,if (f) 相当于 if( f !=0 )

给你一个示例:
  1. #include <stdio.h>
  2. #include <string.h>

  3. int main( void )
  4. {
  5.     unsigned a = 0x80000000; // 看好,这里不是0
  6.     float b;
  7.     memcpy( &b, &a, sizeof(b) );

  8.     if( b )
  9.         printf( "true\n" );
  10.     else
  11.         printf( "false\n" ); // 执行这一句

  12.     return 0;
  13. }
复制代码
b的位模式和整型0是不一样的,但仍然执行else那句。

C标注如是说:
if( expression ) statement
The substatement is executed if the expression compares unequal to 0.

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
4 [报告]
发表于 2015-09-24 16:26 |只看该作者
回复 3# bruceteen


你这段代码被gcc4.4.7编译成了如下汇编代码,条件判断被直接干掉了
gcc -Wall -O2 test.c -S
  1.         .file   "test.c"
  2.         .section        .rodata.str1.1,"aMS",@progbits,1
  3. .LC0:
  4.         .string "false"
  5.         .text
  6.         .p2align 4,,15
  7. .globl main
  8.         .type   main, @function
  9. main:
  10. .LFB30:
  11.         .cfi_startproc
  12.         movl    $.LC0, %edi
  13.         subq    $8, %rsp
  14.         .cfi_def_cfa_offset 16
  15.         call    puts
  16.         xorl    %edi, %edi
  17.         call    exit
  18.         .cfi_endproc
  19. .LFE30:
  20.         .size   main, .-main
  21.         .ident  "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-16)"
  22.         .section        .note.GNU-stack,"",@progbits
复制代码

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2015-09-24 16:30 |只看该作者
回复 2# hellioncu


   
同意,强烈建议不要这么用,编译器如何私下处理这种东西是难以测度的

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
6 [报告]
发表于 2015-09-24 16:35 |只看该作者
回复 4# safedead
这是两回事
之所以会优化掉,是因为编译器知道if(f)必然不成立;之所以知道if(f)必然不成立,是因为f在编译期间就确定了0值。

或者这么说:
假如你用 scanf 输入 a 值 0x80000001,那么编译器就没法优化,但依然输出 false
   

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
7 [报告]
发表于 2015-09-24 16:54 |只看该作者
回复 6# bruceteen

我把代码稍微改了下
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdint.h>
  4. #include <stdlib.h>
  5. #include <unistd.h>

  6. int foo(float b)
  7. {
  8.         if( b )
  9.                 printf( "true\n" );
  10.         else
  11.                 printf( "false\n" );

  12.         return 0;
  13. }

  14. int main(int argc, char *argv[])
  15. {
  16.         foo(0.0f);
  17.         foo(0.1f);
  18.         exit(EXIT_SUCCESS);
  19. }
复制代码
编译执行:

[root@sxy-lenovo ~]# gcc -Wall -O2 test.c
[root@sxy-lenovo ~]# ./a.out
false
true

很有趣是不?(虽然是恶趣味)

查看汇编代码,if那句被翻译成下面这段:
  1.         ucomiss .LC0(%rip), %xmm0
  2.         jp      .L9
  3.         jne     .L9
复制代码
看到这段我就震惊了,jne的含义好说,不等于,jp是啥意思?为奇数!

楼主贴的代码看来没大家想的那么简单,如果是产品代码,里面估计还有其它含义

论坛徽章:
0
8 [报告]
发表于 2015-09-24 18:17 |只看该作者
本帖最后由 linjxwell 于 2015-09-24 18:22 编辑

回复 7# safedead

应该没什么神秘的含义, 主要是那个 union 的代码, 原来是
  1. if (gv.fValue)
复制代码
后来被人改掉了, 改为
  1. if (gv.nValue)
复制代码
并写上注释说(大意): 用 float 作 bool 是不对的

然后我就不知道为什么不行?
如果是我改的话, 我会改为
  1. if (gv.fValue > 0.0f)
复制代码
因为代码后面是 gv.fValue 的值去乘其他的数, 所以, 这里 if 语句主要是判断不等于 0 的情况, 但是又因为用到了 union, 所以, 感觉改的不对, 而又有疑惑~
而我又没学过汇编..

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
9 [报告]
发表于 2015-09-24 19:50 |只看该作者
回复 8# linjxwell


汇编不能用于理解C语言语法,仅仅能作为一个实现的参考
float不是简单的数据,它是有特定结构的,有兴趣的话可以去看IEEE754浮点数的资料
正因为它具有特定结构,所以不能简单的比较

在if语句中,使用float通常要用标准的浮点表达式,常见的规则之一就是不推荐用 "=="去和浮点常数比较
一个简单的10进制浮点数转化为2进制浮点数很可能变成无限循环小数从而产生误差

   

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
10 [报告]
发表于 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) 相关的内容
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP