与0的爱恨纠缠

本文详细讨论了C语言中bool类型与零值的比较,指出C99引入的标准bool类型,以及在不同平台间跨平台性的考虑。同时探讨了浮点数的精度问题,强调了比较浮点数时应避免绝对相等比较,推荐使用精度范围比较。
摘要由CSDN通过智能技术生成

目录

bool变量与"零值"比较

float变量与"零值"比较


bool变量与"零值"比较

深入理解C 中 bool

C语言有没有bool类型? c99之前,主要是c90是没有的,目前大部分书,都是认为没有的。因为书,一般都要落后于行业。 但是c99引入了_Bool类型(你没有看错,_Bool就是一个类型,不过在新增头文件stdbool.h中,被重新用宏写成了 bool,为了保证C/C++兼容性)。

//测试代码1
#include <stdio.h>
#include <stdbool.h> //没有这个头文件会报错,使用新特性一定要加上

int main()
{
   bool ret = false;
   ret = true;
   printf("%zu\n", sizeof(ret)); //vs2022 和 Linux中都是1

   return 0;
}
//查看源码
/* stdbool.h standard header */
//stdbool.h
#ifndef _STDBOOL
#define _STDBOOL
#define __bool_true_false_are_defined 1
#ifndef __cplusplus
#define bool _Bool //c99中是一个关键字哦,后续可以使用bool
#define false 0 //假
#define true 1 //真

理论上,表示真假,需要一个bit就够了,不过这个问题,还是要取决于编译器的理解。vs2022中认为是1个字节

那么问题来了

代码怎么写:因为目前编译器对C99特性支持的并不全面,我们后面依旧默认使用C90的认识去编码即可,使用int表示真 假。 具体要结合实际情况去定。

but ! !

//在vs中,看看下面的代码
//测试代码2
#include <stdio.h>
int main()
{
  //在vs中,光标选中BOOL,单击右键,可以看到转到定义,就能看到BOOL是什么
  BOOL ret = FALSE;
  ret = TRUE;
  printf("%d\n", sizeof(ret)); //输出结果是4,因为在源代码中,是这么定义的:typedef int BOOL;

  return 0;
}

 我们发现,竟然也能编过。。。什么鬼??

这都是Microsoft自己搞的一套BOOL值。在vs中转到BOOL对应的头文件,翻到最上面,就能看到微软的版权信息。

好了,该听谁的??

微软?强烈不推荐,因为好的习惯是:一定要保证代码的跨平台性,微软定义的专属类型,其他平台不支持。(以后在语言编程层面上,凡是直接使用和平台强相关的内容,我都不推荐。(不是针对谁蛤))

跨平台性?

我们可以看到上面测试代码1,和测试代码2 在vs2013下都能编过(微软系的), 但是在Linux中(centos 7),测试代码1,是可以编过的(因为是标准啊),但是测试代码2就过不了。(Linux后期会讲,由于本人还没有深入学习Linux,所有就先不举例了,大家只需要知道测试代码2在Linux中不能通过就行了)

所以,后面万一要用bool,强烈推荐C99标准的,摒弃微软

总结: 1. 优先使用c90,就是我之前以及后面一直用的方式 2. 万一非得使用bool,推荐c99标准,不推荐MS自定义。

 C中如何进行 bool 值与0比较呢?

#include <stdio.h>
#include <stdbool.h>
int main()
{
   int pass = 0; //0表示假,C90,我们习惯用int表示bool
   //bool pass = false; //C99
   if (pass == 0){ //理论上可行,但此时的pass是应该被当做bool看待的,==用来进行整数比较,不推荐
  //TODO  TODD表示if语句中执行内容的省略
  }
  if (pass == false){ //不推荐,尽管在C99中也可行
     //TODO
  }
  if (pass){ //推荐
    //TODO
  }
//理论上可行,但此时的pass是应该被当做bool看待的,==用来进行整数比较,不推荐
//另外,非0为真,但是非0有多个,这里也不一定是完全正确的
  if (pass != 1){
    //TODO
  }
  if (pass != true){ //不推荐,尽管在C99中也可行
     //TODO
  }
  if (!pass){ //推荐
     //TODO
  }

  return 0;
}

 结论:bool类型,直接判定,不用操作符进行和特定值比较。

float变量与"零值"比较

这里比较复杂,要理清楚更细节的内容,需要知道浮点数在内存中的存储原理,涉及篇幅很多,我们暂时不讲。 如果想了解更多细节,大家可以补一下浮点数的存储-CSDN博客中关于浮点数存储的细节

//浮点数在内存中存储,并不想我们想的,是完整存储的,在十进制转化成为二进制,是有可能有精度损失的。

//注意这里的损失,不是一味的减少了,还有可能增多。浮点数本身存储的时候,在计算不尽的时候,会“四舍五入”或者其他 策略

 

结论:因为精度损失问题,两个浮点数,绝对不能使用==进行相等比较.  

//那么两个浮点数该如何比较呢?

//应该进行范围精度比较

//伪代码
if((x-y) > -精度 && (x-y) < 精度)
{
    //TODO
}
//伪代码-简洁版
if(fabs(x-y) < 精度)  //fabs是浮点数求绝对值
{
    //TODO
}

精度:

自己设置?后面如果有需要,可以试试,通常是宏定义。

使用系统精度?暂时推荐

#include<float.h>   //使用下面两个精度,需要包含该头文件

DBL_EPSILON //double 最小精度

FLT_EPSILON //float 最小精度

//两个精度定义
#define DBL_ EPSILON 

2.2204460492503131e-016   /* smallest such that 1. 0+DBL_ EPSILON !=1.0 */
#define FLT_ EPSILON
1.192092896e-07F   /* smallest such that 1.0+FLT_ EPSILON !=1.0 */
XXX_ EPSILON是最小误差,是: XXX_ EPSILON+n不等于n的最小的正数。
EPSILON这个单词翻译过来是'∈'的意思,数学上,就是极小的正数
 

 等等,你不是要讲float变量与0比较嘛,和上面有什么关系?

//最终代码
#include <stdio.h>
#include <math.h>
#include <float.h>
int main()
{
  double x = 0.00000000000000000000001;

  //if (fabs(x-0.0) < DBL_EPSILON){ //写法1
  //if (fabs(x) < DBL_EPSILON){ //写法2
  if(x > -DBL_EPSILON && x < DBL_EPSILON){  //书中写法(C语言深度解剖)->推荐
      printf("you can see me!\n");
  }
  else{
      printf("oops\n");
  }

  return 0;
}
//x > -DBL_EPSILON && x < DBL_EPSILON: 为何不是>= && <= 呢?
//个人看法:XXX_EPSILON是最小误差,是:XXX_EPSILON+n不等于n的最小的正数。
//XXX_EPSILON+n不等于n的最小的正数: 有很多数字+n都可以不等于n,但是XXX_EPSILON是最小的,but,
XXX_EPSILON依旧是引起不等的一员。
//换句话说:fabs(x) <= DBL_EPSILON(确认x是否是0的逻辑),如果=,就说明x本身,已经能够引起其他和他+-的数据本身的变化了,这个不符合0的概念。

今天的内容就到这里了,如果对您有帮助的话麻烦点赞+关注哦!!

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值