《C语言深度剖析》第一章 关键字详解 p2 C语言从入门到入土(进阶篇)

目录

1.signed、unsigned

1.1整形在内存的存储

1.2signed(有符号数)

1.3unsigned(无符号数)

2 if else 组合

3 各种变量与“零值”进行比较

3.1 bool 变量与"零值"进行比较

3.2 float 变量与"零值"进行比较

3.3 指针变量与“零值”进行比较


本章节文章是作者通过观看《C语言深度剖析》等各种资料总结的精华,基础部分省略了不少,是为了让大家能够更加深入了解C语言的魅力!因为为了避免与之前的文章发生赘述,所以就直接讲作者认为的精华部分哈!现在正文开始! 

 谁都不能阻挡你成为更优秀的人。

1.signedunsigned

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 组合

语法结构:
//1
if
(
表达式
)
        语句
;
//2
if
(
表达式
)
        语句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
类型?
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
比较呢
?
#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
类型,直接判定,不用操作符进行和特定值比较。

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
配对呢?

其实并不是看着这样的理解,推荐的写法是:

 总结:else 匹配采取就近原则

今天的内容就到这里了哈!!!

要是认为作者有一点帮助你的话!

就来一个点赞加关注吧!!!当然订阅是更是求之不得!

最后的最后谢谢大家的观看!!!

你们的支持是作者写作的最大动力!!!

下期见哈!!!

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>