《C语言深度剖析》第一章 关键字详解 p2 C语言从入门到入土(进阶篇)
目录
本章节文章是作者通过观看《C语言深度剖析》等各种资料总结的精华,基础部分省略了不少,是为了让大家能够更加深入了解C语言的魅力!因为为了避免与之前的文章发生赘述,所以就直接讲作者认为的精华部分哈!现在正文开始!
谁都不能阻挡你成为更优秀的人。
1.signed、unsigned
1.1整形在内存的存储
也就是说,在补码进去之前是不管b的,是进入空间之后再转化为b(同时看b的类型算出值)(此时才看b的类型)。
总结:数据在存储时,是先转换为二进制,同时开辟了一块空间,然后将数据源储存进空间的时候再看其类型,然后解释其二进制位。(这里可能会发生整型提升)
PS:补充一个二进制快速转换口诀,n次方就后面n个0,前面一个1。
1.2signed(有符号数)
首先,对于有符号数,一定要能表示该数据是正数还是负数。所以我们一般用最高比特位来进行充当符号位。原码、反码、补码计算机中的有符号数有三种表示方法,即原码、反码和补码。三种表示方法均有符号位和数值位两部分,符号位都是用
0
表示
“
正
”
,用
1
表示
“
负
”
,而数值位三种表示方法各不相同。如果一个数据是负数,那么就要遵守下面规则进行转化:原码:直接将二进制按照正负数的形式翻译成二进制就可以。反码:将原码的符号位不变,其他位依次按位取反就可以得到了。补码:反码
+
1
就得到补码。如果一个数据是正数,那么它的原反补都相同。
1.3unsigned(无符号数)
不需要转化,也不需要符号位,原反补相同。
对于整形来说:数据存放内存中其实存放的是补码。
为什么都是补码
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理; 同时,加法和减法也可以统一处理(
CPU
只有加法器)。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
取值范围
总结规律:整数的取值范围无符号:
[
0
,
2
^n
-
1
]有符号:
[
-
2
^
(
n
-
1
),
2
^
(
n
-
1
)
-
1
]
2 if else 组合
语法结构://1if
(
表达式
)语句
;//2if
(
表达式
)语句1
;else语句2
;//3.
多分支if
(
表达式
1
)语句1
;else if
(
表达式
2
)语句2
;else语句3
;//4.
嵌套if
(
表达式
1
){语句1
;if
(
表示式
x
){语句x
;}else
{语句y
;}}else if
(
表达式
2
){语句2
;}else
{语句3
;}
3 各种变量与“零值”进行比较
3.1 bool 变量与"零值"进行比较
深入理解
C
中
bool
C
中
bool
C
语言有没有
bool
类型?c99
之前,主要是
c90
是没有的,目前大部分书,都是认为没有的。因为书,一般都要落后于行业。但是
c99
引入了
_Bool
类型(你没有看错,
_Bool
就是一个类型,不过在新增头文件
stdbool
.
h
中,被重新用宏写成了bool,为了保证
C
/
C
++
兼容性)。
//测试代码1
#include <stdio.h>
#include <stdbool.h>
//没有这个头文件会报错,使用新特性一定要加上
#include <windows.h>
int main()
{
bool ret = false;
ret = true;
printf("%dn", sizeof(ret));
//vs2013 和 Linux中都是1
system("pause");
return 0;
}
PS:理论上,表示真假,需要一个bit就够了,不过这个问题,还是要取决于编译器的理解。vs2013中认为是1个字节。
但是:
//在vs中,看看下面的代码
//测试代码2
#include <stdio.h>
#include <windows.h>
int main()
{
//在vs中,光标选中BOOL,单击右键,可以看到转到定义,就能看到BOOL是什么
BOOL ret = FALSE;
ret = TRUE;
printf("%dn", sizeof(ret));
//输出结果是4,因为在源代码中,是这么定义的:typedef int BOOL;
system("pause");
return 0;
}
这都是Microsoft自己搞的一套BOOL值。在vs中转到BOOL对应的头文件,翻到最上面,就能看到微软的版权信息。好了,该听谁的??现在有两种1/4。
微软?强烈不推荐,因为好的习惯是:一定要保证代码的跨平台性,微软定义的专属类型,其他平台不支持。(以后在语言编程层面上,凡是直接使用和平台强相关的内容,我们都不推荐。(不是针对谁哈))跨平台性?我们可以看到上面测试代码
1
,和测试代码
2
在
vs2013
下都能编过(微软系的)
,但是在
Linux
中
(
centos
7
),
测试代码
1
,是可以编过的
(
因为是标准啊
)
,但是测试代码
2就过不了。所以,后面万一要用
bool
,强烈推荐
C99
标准的,摒弃微软总结:1.
优先使用
c90
,
就是我们之前以及后面一直用的方式2.
万一非得使用
bool
,推荐
c99
标准,不推荐
MS
自定义。
那么,
C
中如何进行
bool
值与
0
比较呢
?
C
中如何进行
bool
值与
0
比较呢
?
#include <stdio.h>
#include <stdbool.h>
#include <windows.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
}
system("pause");
return 0;
}
结论:
bool
类型,直接判定,不用操作符进行和特定值比较。
bool
类型,直接判定,不用操作符进行和特定值比较。
3.2 float 变量与"零值"进行比较
浮点数在内存中存储,并不想我们想的,是完整存储的,在十进制转化成为二进制,是有可能有精度损失的。注意这里的损失,不是一味的减少了,还有可能增多。浮点数本身存储的时候,在计算不尽的时候,会
“
四舍五入
”或者其他策略
结论:因为精度损失问题,两个浮点数,绝对不能使用==进行相等比较.
那么两个浮点数该如何比较呢?
应该进行范围精度比较:
#include<float.h>
//使用下面两个精度,需要包含该头文件
DBL_EPSILON //double 最小精度
FLT_EPSILON //float 最小精度
//伪代码
if((x-y) > -精度 && (x-y) < 精度){
//TODO
}
//伪代码-简洁版
if(fabs(x-y) < 精度){
//fabs是浮点数求绝对值
//TODO
}
精度:
自己设置?后面如果有需要,可以试试,通常是宏定义。
使用系统精度?暂时推荐
//代码调整后
#include <stdio.h>
#include <math.h>
//必须包含math.h,要不然无法使用
fabs #include <float.h>
//必须包含,要不然无法使用系统精度
#include <windows.h>
int main()
{
double x = 1.0;
double y = 0.1;
printf("%.50fn", x - 0.9);
printf("%.50fn", y);
if (fabs((x - 0.9) - y) < DBL_EPSILON){ //原始数据是浮点数,我们就用DBL_EPSILON
printf("you can see me!n");
}
else{
printf("oopsn");
}
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
这个单词翻译过来是
'ε'
的意思,数学上,就是极小的正数
所以我们再回来讲float和0的比较:
#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("oopsn");
}
system("pause");
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
的概念。
3.3 指针变量与“零值”进行比较
其实NULL 和 '/0' 和 0 都是0。只不过因为编译器编译的时候需要相同的类型进行计算,所以就有了“各种不同的0”。
else
到底与哪个
if
配对呢?
到底与哪个
if
配对呢?
其实并不是看着这样的理解,推荐的写法是:
总结:else 匹配采取就近原则
今天的内容就到这里了哈!!!
要是认为作者有一点帮助你的话!
就来一个点赞加关注吧!!!当然订阅是更是求之不得!
最后的最后谢谢大家的观看!!!
你们的支持是作者写作的最大动力!!!
下期见哈!!!
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
二维码