if 语句的3种比较
首先我们知道
if
是用来判断真假的。
C语言中规定:0表示假,非0表示真。
if
语句的执行过程如下
int main()
{
int flag = 1;
//1.先执行()中的表达式或某中函数,得到的布尔(真假)结果。
//2.条件 判断分支
//3.进行 分支功能
if (1 == flag)
{
printf("hello world\n");
}
else
{
printf("NO\n");
}
return 0;
}
什么是语句
C语言中由一个分号;隔开的就是一条语句。
比如:
printf("hehe);
1+2;
什么是表达式
C语言中,用各种操作符把变量连起来,形成有意义的式子,就叫做表达式。(非官方定义) 操作符:+,-,*,/,%,>,<,=,==...
bool 变量和 0 比较
深入理解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("%d\n", sizeof(ret));//vs2013 和 Linux中都是1
return 0;
}
查看源码
#ifndef _STDBOOL
#define _STDBOOL
#define __bool_true_false_are_defined 1
#ifndef __cplusplus
#define bool _Bool //c99中是一个关键字哦,后续可以使用bool
#define false 0 //假
#define true 1 //真
#endif /* __cplusplus */
#endif /* _STDBOOL */
理论上,表示真假,需要一个bit就够了,不过这个问题,还是要取决于编译器的理解。vs2013中认为是1个字节。
注意:因为目前编译器对C99特性支持的并不全面,我们后面依旧默认使用C90的认识去编码即可,使用int表示真假。
VS版的布尔值
测试代码2
#include <windows.h> //VS版的要加这个头文件
int main()
{ //在vs中,光标选中BOOL,单击右键,可以看到转到定义,就能看到BOOL是什么
BOOL ret = FALSE;
ret = TRUE;
printf("%d\n", sizeof(ret)); //输出结果是4,因为在源代码中,是这么定义的:typedef int BOOL;
return 0;
}
微软的强烈不推荐,因为好的习惯是:一定要保证代码的跨平台性,微软定义的专属类型,其他平台不支持。(以后在语言 编程层面上,凡是直接使用和平台强相关的内容,我们都不推荐。(不是针对谁蛤)
关于跨平台性
我们可以看到上面测试代码1,和测试代码2 在vs2013下都能编过(微软系的), 但是在Linux中(centos 7),测试代码1,是可以编过的(因为是标准啊),但是测试代码2就过不了。
以后万一要用bool,强烈推荐C99标准的,摒弃微软
总结:
- 优先使用c90,就是我们之前以及后面一直用的方式
- 万一非得使用bool,推荐c99标准,不推荐MS自定义。
#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
}
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类型,直接判定,不用操作符进行和特定值比较
浮点数和 0 比较
这里比较复杂,要理清楚更细节的内容,需要知道浮点数在内存中的存储原理.
请参考我之前写的博客
链接: 深度剖析数据在内存中的存储
浮点数在内存中存储,并不想我们想的,是完整存储的,在十进制转化成为二进制,是有可能有精度损失的。
注意这里的损失,不是一味的减少了,还有可能增多。浮点数本身存储的时候,在计算不尽的时候,会“四舍五入”或者其他策略
解释一下
#include <stdio.h>
int main()
{
double x = 3.6; //浮点数在内存中默认是double的类型
printf("%.50f\n", x);
return 0;
}
int main()
{
double x = 1.0;
double y = 0.1;
printf("%.50f\n", x - 0.9);
printf("%.50f\n", y);
if ((x - 0.9) == y)
{
printf("you can see me!\n");
}
else
{
printf("oops\n");
}
return 0;
}
double x = 1.0;
数据储存中先开辟空间,再有二进制,然后把二进制写到空间中。
结论: 因为精度损失问题,两个浮点数,绝对不能使用==进行相等比较.
浮点数比较
进行范围精度比较
int main()
{
double x = 1.0;
double y = 0.1;
//伪代码
if((x-y) > -精度 && (x-y) < 精度)
{
//TODO
}
//伪代码-简洁版
if(fabs(x-y) < 精度)//fabs是浮点数求绝对值
{
//TODO
}
return 0;
}
比较原理
精度: 可以自己设置,后面如果有需要,可以试试,通常是宏定义。或使用系统精度
#include <stdio.h>
#include <math.h> //必须包含math.h,要不然无法使用fabs
#include <float.h> //必须包含,要不然无法使用系统精度
int main()
{
double x = 1.0;
double y = 0.1;
printf("%.50f\n", x - 0.9);
printf("%.50f\n", y);
if (fabs((x - 0.9) - y) < DBL_EPSILON) //原始数据是浮点数,我们就用DBL_EPSILON
{
printf("you can see me!\n");
}
else
{
printf("oops\n");
}
system("pause");
return 0;
}
两个精度定义
#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这个单词翻译过来是’ε’的意思,数学上,就是极小的正数 ----来自百度
另一种写法但是没上面的代码好,不推荐这样写
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <windows.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)
{
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的概念
指针变量和 0 比较
int main()
{
char arr = '\0'; //字符赋0
int a = 0; //数赋0
int* pc = NULL; //指针赋0
printf("%d\n",0);
printf("%d\n", '\0');
printf("%d\n", NULL);
//打印结果一样
return 0;
}
结论: 能用操作符来连接起来的,操作符两边的类型必须是一样的。