目录
本章节文章是作者通过观看《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 类型?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("%d\n", 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("%d\n", 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("%.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 这个单词翻译过来是 'ε' 的意思,数学上,就是极小的正数
所以我们再回来讲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("oops\n");
}
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 匹配采取就近原则
今天的内容就到这里了哈!!!
要是认为作者有一点帮助你的话!
就来一个点赞加关注吧!!!当然订阅是更是求之不得!
最后的最后谢谢大家的观看!!!
你们的支持是作者写作的最大动力!!!
下期见哈!!!