008-进制-C语言笔记

学习目标

1.【掌握】include预处理指令

2.【掌握】多文件开发

3.【了解】认识进制

4.【掌握】进制之间的互相转换

5.【掌握】原码,反码,补码

6.【掌握】位运算

7.【掌握】int类型的修饰符

一、include预处理指令

其实我们早就有接触文件包含这个指令了, 就是#include,它可以将一个文件的全部内容拷贝另一个文件中。

使用语法:

第一种:#include <文件名>

直接到C语言库函数头文件所在的目录中寻找文件

第二种:#include "文件名"

系统会先在源程序当前目录下寻找,若找不到,再到操作系统的path路径中查找,最后才到C语言库函数头文件所在目录中查找

使用注意:

#include指令允许嵌套包含,比如a.h包含b.h,b.h包含c.h,但是不允许递归包含,比如 a.h 包含 b.h,b.h 包含 a.h。下面是错误的用法:

使用#include指令可能导致多次包含同一个头文件,降低编译效率,比如下面的情况:

在one.h中声明了一个one函数;在two.h中包含了one.h,顺便声明了一个two函数。(这里就不写函数的实现了,也就是函数的定义)

假如我想在main.c中使用one和two两个函数,而且有时候我们并不一定知道two.h中包含了one.h,所以可能会这样做:

编译预处理之后main.c的代码是这样的:

 
1
2
3
4
5
6
voidone();
voidone();
voidtwo();
intmain(){
    return0;
}

第1行是由#include "one.h"导致的,第2、3行是由#include "two.h"导致的(因为two.h里面包含了one.h)。可以看出来,one函数被声明了2遍,根本就没有必要,这样会降低编译效率。

为了解决这种重复包含同一个头文件的问题,一般我们会这样写头文件内容:

大致解释一下意思,就拿one.h为例:当我们第一次#include "one.h"时,因为没有定义_ONE_H_,所以第9行的条件成立,接着在第10行定义了_ONE_H_这个宏,然后在13行声明one函数,最后在15行结束条件编译。当第二次#include "one.h",因为之前已经定义过_ONE_H_这个宏,所以第9行的条件不成立,直接跳到第15行的#endif,结束条件编译。就是这么简单的3句代码,防止了one.h的内容被重复包含。

这样子的话,main.c中的:

 
1
2
#include "one.h"
#include "two.h"

就变成了:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// #include "one.h"
#ifndef _ONE_H_
#define _ONE_H_
 
voidone();
 
#endif
 
// #include "two.h"
#ifndef _TWO_H_
#define _TWO_H_
 
// #include "one.h"
#ifndef _ONE_H_
#define _ONE_H_
 
voidone();
 
#endif
 
voidtwo();
 
#endif

第2~第7行是#include "one.h"导致的,第10~第23行是#include "two.h"导致的。编译预处理之后就变为了:

 
1
2
voidone();
voidtwo();

这才是我们想要的结果

二、多文件开发

大家都知道我们的C程序是由1个1个的函数组成的,当我们的程序很大的时候,将这些函数代码写在写在同1个文件之中是绝对不科学。函数太多,不方便管理,并且不利于团队开发。

我们的程序实际上都是分为1个1个的模块的,无论多大的程序都是由1个1个的小功能组成的。模块就是功能相同或者相似的一些函数。在实际开发中,不同的人负责开发不同的功能模块,要使用模块中的功能的话,直接调用就可以了。

如何写模块?

写模块的人,一般情况下要写两个文件。.c文件  .h文件. header 头文件。

.h文件之中,写上函数的声明。

.c文件之中,写上函数的实现。

想要调用模块之中的函数,只需要包含这个模块的头文件就可以了。比如我们使用printf函数需要包含stdio.h头文件一样,只要包含了函数的声明,我们就能直接使用函数了。

例如:

我们还能给函数分组,例如:

右键,选择New Group可以创建组,进行源文件分组管理。放在组里的源文件其实他的路径是不会改变的:

三、认识进制

什么是进制?

进制是记数的一种方式,侧重点在于记数的时候,是逢多少进一。比如我们日常生活中用的十进制,逢10进1。C语言中也有进制,C语言能识别的进制有二进制,十进制,八进制,十六进制。多少多少进制就是逢多少进1。

二进制:

逢二进一,每1位用0和1表示。

在C语言的代码中,如果要写1个二进制的数,那么就必须要在这个二进制的数的前面加1个0b的前缀。

C语言没有提供1个个是控制符来将1个整形变量中的数据以二进制的形式输出。

八进制:

逢八进一,每1位 0、1、2、3、4、5、6、7中的任意1位来表示。

在C语言之中,如果要写1个八进制的数,那么就必须要在这个八进制的数的前面加1个前缀0。

%o 会将整形变量中的数据以八进制的形式输出。

十进制:

逢十进一,每1位 0 1 2 3 4 5 6 7 8 9 中的任意一位,逢十进一。

在C语言之中直接写1个整数,默认就是十进制。

%d 是将整形变量中的数据以十进制的形式输出。

十六进制:

逢十六进以,每1位 0 1 2 3 4 5 6 7 8 9 a b c d e f 中的任意1位来表示。

如果我们要在C语言中写1个十六进制的数 那么就必须要在这个数的前面加1个前缀0x。

使用%x 将整形变量中的数据以十六进制的形式输出。

例如:

 
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
 
intmain(intargc,constchar*argv[]){
  
    intnum=0x13adf0;//加0x表示十六进制
    
    printf("num = %x\n",num);//%x以十六进制形式打印
    
    return0;
}

四、进制直接的互相转换

我们先来引入一个概念,当然,C语言中没有规定这些,是便于学习者进行按位运算而自己定义的概念。

数码:一个数的每一位数字,就叫做数码。

数位:数码在这个数中的位置,从右到左,从0开始增长。

基数:每一位数码最多可以由多少个数字来表示,多少进制就是多少基数。

位权 = 数码 * (基数的数位次方)

进制之间的转换:

十进制转二进制:除2取余,直到商为0,再余数倒序

十进制转八进制:除8取余,直到商为0,再余数倒序

十进制转十六进制:除16取余,直到商为0,再余数倒序

二进制转十进制:每一位的位权相加

八进制转十进制:每一位的位权相加

十六进制转十进制:每一位的位权相加

二进制转换八进制:3合1,低位到高位,每3位分成一组,高位不够补0,求出每一组的10进制,再相连

八进制转二进制:3拆1,将八进制的每1个数码,拆成1个三位的二进制,再将这些二进制连起来

二进制转十六进制:4合1,低位到高位,每四位分成1组,高位不够补0,求出每1组的10进制,再相连

十六进制转二进制:1拆4,将十六进制的每1个数码,拆成1个四位的二进制1再将这些二进制连起来

八进制转十六进制:八进制 -> 二进制 ->十六进制

打印二进制的函数:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
 
//传入一个整数,打印他的二进制
voidprintBinary(intnum){
    //定义一个临时变量temp,储存位移后的数据
    inttemp=0;
    //定义一个临时变量temp1,储存按位与后的二进制最低位数值
    inttemp1=0;
    for(inti=0;i<32;i++){
        //先位移,截取数据
        temp=num>>(31-i);
        //再与1按位与,因为任何数与1与都能得到那个任何数的二进制的最低位
        temp1=temp&1;
        //取出一位打印一位
        printf("%d",temp1);
    }
    printf("\n");
}
 
intmain(intargc,constchar*argv[]){
    
    //调用函数打印出整数的二进制
    printBinary(100);
    
    return0;
}

自己随意写的,网上还有很多功能更多的进制转换函数,需要的自己去谷歌吧。

五、原码,反码,补码

声明1个变量,其实就是在内存之中申请指定字节数的空间,用来存储数据。无论任何数据在内存之中都是以其二进制的形式存储的,并且是以这个数据的二进制的补码的形式存储的。那什么是补码呢?原码、反码、补码 都是二进制,只不过是二进制的不同的表现形式。

强调:所有的数据都是以其二进制的补码的形式存储在内存之中的。

原码:

最高位用来表示符号位,0代表正,1代表负。其他叫数值位,数值位是这个数的绝对值的二进制位。

 
1
2
3
9的原码: 00000000000000000000000000001001
 
-3的原码:10000000000000000000000000000011

反码:

正数的反码就是其原码。负数的反码,是在其原码的基础之上,符号位不变,数值位取反。

 
1
2
3
4
5
6
7
9的原码: 00000000000000000000000000001001
 
9的反码: 00000000000000000000000000001001
 
-3的原码:10000000000000000000000000000011
 
-3的反码:11111111111111111111111111111100

补码:

正数的补码就是,其原码。负数的补码,是在其反码的基础之上加1。

 
1
2
3
4
5
6
7
8
9
10
11
9的原码:00000000000000000000000000001001
 
9的反码:00000000000000000000000000001001
 
9的补码:00000000000000000000000000001001
 
-3的原码:10000000000000000000000000000011
 
-3的反码:11111111111111111111111111111100
 
-3的补码:11111111111111111111111111111101

为什么要用补码来储存数据,因为计算机之中只有加法,没有减法。为了更低成本的计算出结果,所以使用补码来存储数据。如下例子:3 + (-2) = 1

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
原码计算:
00000000000000000000000000000011
10000000000000000000000000000010相减
------------------------------------
10000000000000000000000000000101  这个结果不对.已经变成负数了.
 
 
反码计算:
00000000000000000000000000000011
11111111111111111111111111111101相减
-------------------------------------
00000000000000000000000000000000   0这也是错的.
 
 
补码计算:
00000000000000000000000000000011
11111111111111111111111111111110相减
-------------------------------------
00000000000000000000000000000001   1   1结果是对.

六、位运算

什么叫做位运算?

1个二进制数的每1位来参与运算,参与位运算的前提,是这个数必须是二进制数。并且参与运算的二进制数据必须是补码的形式,并且算出来的结果也是补码。

按位与  &

指的是两个数的二进制的补码 按位进行与运算. 如果都为1 结果就为1 否则就为0.

 
1
2
3
4
5
6
3&2;
 
00000000000000000000000000000011
00000000000000000000000000000010
------------------------------------
00000000000000000000000000000010

注意:任何数按位与1,结果是这个数的最低位

 
1
2
3
4
5
3&1;
00000000000000000100100010010001
00000000000000000000000000000001
--------------------------------------
00000000000000000000000000000001

偶数的最低位一定是0,奇数的最低位一定是1。用1个数去按位与1,如果结果为0那么这个数一定是1个偶数,如果结果为1,那么这个数一定是1个奇数。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
 
intmain(){
  
    intnum=100;
    //任意数按位与1,都能得到他的二进制位的最低位,如果最低位是1,则是奇数,是0则是偶数。
    if(num&1==0){
        printf("偶数\n");
    }else{
        printf("奇数\n");
    }
    return0;
}

按位或  |

参与按位或的二进制补码,只要有1位为1,那么结果就为1,只有都为0的时候才为0。

 
1
2
3
4
5
6
3|2;
 
00000000000000000000000000000011
00000000000000000000000000000010
-------------------------------------
00000000000000000000000000000011

按位取反  ~

这是1个单目运算符,只需要1个数据参与,将1变0,0变1

 
1
2
3
4
5
6
~3;
 
00000000000000000000000000000011
11111111111111111111111111111100补码
11111111111111111111111111111011反码
10000000000000000000000000000100-4

按位异或  ^

参与按位异或的二进制补码,每一位,相同为0,不同为1。

 
1
2
3
4
5
6
3^5;
 
000000000000000000000000000000011
000000000000000000000000000000101
----------------------------------------
000000000000000000000000000000110+6

实现交换两个变量的值:

 
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
 
intmain(){
  
    intnum1=10,num2=20;
    num1=num1^num2;
    num2=num1^num2;
    num1=num1^num2;
    printf("num1 = %d,num2 = %d\n",num1,num2);
    return0;
}

按位左移  <<

1个二进制补码按位左移,就是将这个二进制位,向左移动指定的位数,溢出部分丢弃 低位补零。

 
1
2
3
4
5
3<<2;
3的补码按位左移2位.
 
00000000000000000000000000000011
00000000000000000000000000001100+12

注意:

1个数按位左移,有可能改变其正负性。

1个数按位左移n位,相当于这个数乘以2的n次方。

16 << 3;  相当于16 * 2的3次方。就是16*8=128

按位右移  >>

参与按位右移的二进制的补码,向右移动指定的位数,溢出部分补齐,高位补符号位。

 
1
2
3
4
3>>2;
 
00000000000000000000000000000011
00000000000000000000000000000000  0

注意:

1一个数按位右移,不会改变1个数的正负性。

1个数按位右移n位,相当于这个数除以2的n次方。

六、int类型的修饰符

我们声明1个int类型的变量,会在内存之中申请4个字节的空间,可以存储的数据-2147483647到+2147483648之间的整数。可是有的时候,数据要不了那么大,4个字节就显得很浪费。而有的时候,数据太大,4个字节又不够。这个时候,我们就可以使用int类型的修饰符来解决这个问题了。

int类型的修饰符有short,long,long long。他们可以限定int类型的变量在内存之中占据多少个字节。

short

被short修饰的int变量,在内存之中占据2个字节。在不考虑正负的情况可以表示65536个数。最高位表示符号位可以储存-32767到+32768之间的整数。我们可以使用%hd来输出short int 变量的值,如果要声明short int变量的话. 可以省略int。比如:short num = 12;

long

被long修饰的int变量,在内存之中占据8个字节(64位编辑器),使用%ld,输出long int变量的值。并且如果要声明1个long int变量,可以省略int。比如: long num = 100;

long long

被long long 修饰的int变量无论是多少位的系统都占据8个字节,使用%lld来输出long long int 变量的值。并且也可以省略int 。比如: long long num = 100;

unsigned

我们声明1个int类型的变量,占据4个字节,最高位用来表示符号位。但是我们可以使用1个关键字,让这个变量的最高位不表示符号位,全部位数都用来表示数据。这样最小值就只能存储0,但是最大值可以翻番。

signed

要求变量的最高位用来表示符号位,默认就是这样的。所以这个关键词一般没啥用。

008-进制-C语言笔记的更多相关文章

  1. C语言学习笔记:15_c语言中的进制操作.c

    /* * 15_c语言中的进制操作.c * * Created on: 2015年7月5日 * Author: zhong */ #include <stdio.h> #include & ...

  2. C/C++编程笔记:C语言进制详解,二进制、八进制和十六进制!

    我们平时使用的数字都是由 0~9 共十个数字组成的,例如 1.9.10.297.952 等,一个数字最多能表示九,如果要表示十.十一.二十九.一百等,就需要多个数字组合起来. 例如表示 5+8 的结果 ...

  3. 【学习笔记】【C语言】进制

    1. 什么是进制 是一种计数的方式,数值的表示形式 2. 二进制 1> 特点:只有0和1,逢2进1 2> 书写格式:0b或者0b开头 3> 使用场合:二进制指令\二进制文件,变量在内 ...

  4. c语言学习笔记(5)——进制

    进制 1.什么叫进制?  逢n进1: 2.把r进制转成十进制 a*r^0+b*r^1+c*r^2..... 3.把十进制转成r进制 185----->(r进制) 185不停的除r取余,最后把余数 ...

  5. C语言学习笔记之进制之间的转换

    这一篇主要是对进制之间转换的讲解,方便查看,以防忘记 二进制      逢二进一 八进制      逢八进一                以0开头, 0就是8进制的标志 十进制      逢十进一 ...

  6. iOS阶段学习第二天笔记(数据类型与进制)

    iOS学习(C语言)知识点整理笔记 1.C语言32个关键字 一.存储相关 1)auto 声明自动变量 2)register 声明寄存器变量 3)volatile 声明的变量在程序执行过程中可能被隐含的 ...

  7. matlab学习笔记10_6 字符串与数值间的转换以及进制之间的转换

    一起来学matlab-matlab学习笔记10 10_6 字符串与数值间的转换以及进制之间的转换 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考书籍 <matlab 程序设计与综合 ...

  8. C++笔记(7)——一些模拟题:简单模拟、查找元素、图形输出、日期处理、进制转换、字符串处理

    以下内容基本来自<算法笔记>,作者为胡凡,建议直接买书看,我这里只是摘抄部分当笔记,不完整的. 简单模拟 就是一类"题目怎么说你就怎么做"的题目.这类题目不涉及算法,只 ...

  9. c语言将2进制数转化为10进制数(栈的初始化,进栈,出栈)

    //c语言描述 将2进制转化为10进制 #include <stdio.h> #include <stdlib.h> #include <math.h> #defi ...

随机推荐

  1. 浏览器与DNS解析过程

    浏览器解析 1.地址栏输入地址后,浏览器检查自身DNS缓存 地址栏输入chrome://net-internals/#dns 查看. 2.浏览器缓存中未找到,那么Chrome会搜索操作系统自身的DNS ...

  2. 什么是DevOps ?

    DevOps字面理解 DevOps(Development和Operations组合)是一组过程.方法与系统的统称,用于促进开发(应用程序/软件工程).技术运营和质量保障(QA)部门之间的沟通.协作与 ...

  3. FormDataMultiPart获取表单文件的大小

    在完成springboard某个功能时遇到个问题,前端表单上传了个文件,服务端接收的是FormDataMultiPart,希望通过FormDataMultiPart拿到上传文件的size. 一开始获取 ...

  4. 移动深度学习 Mobile-deep-learning(MDL)

    Free and open source mobile deep learning framework, deploying by Baidu. This research aims at simpl ...

  5. Pandas 精简实例入门

    目录 0. 案例引入 1. Pandas 主要数据结构 1.1 DataFrame 1.1.1 设置索引 1.1.2 重设索引 1.1.3 以某列为索引 1.2 MultiIndex 1.3 Seri ...

  6. coding++ :javascript Date format (js日期格式化)

    方式一: // 对Date的扩展,将 Date 转化为指定格式的String // 月(M).日(d).小时(h).分(m).秒(s).季度(q) 可以用 1-2 个占位符, // 年(y)可以用 1 ...

  7. LeetCode#1047-Remove All Adjacent Duplicates In String-删除字符串中的所有相邻重复项

    一.题目 给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们. 在 S 上反复执行重复项删除操作,直到无法继续删除. 在完成所有重复项删除操作后返回最终的字符串.答案 ...

  8. jdk安装和配置教程

    目录 jdk的下载 jdk的安装 配置环境变量 验证是否配置成功] 一些常见的错误(待更新) 一.首先是jdk的下载 链接:https://pan.baidu.com/s/1ojQDuCwiGSA7A ...

  9. 模块 re_正则

    模块re_正则 讲正题之前我们先来看一个例子:https://reg.jd.com/reg/person?ReturnUrl=https%3A//www.jd.com/ 这是京东的注册页面,打开页面我 ...

  10. ARDUINO UNO数字引脚端口上电后不稳定状态。

    ARDUINO UNO数字引脚端口上电后不稳定状态. 在使用4*4矩阵键盘时,遇到了输入端的电平无法稳定,一直被识别为高电平. 在发现这一问题后,首先检查程序是否出错.检查后发现程序没有任何问题. 于 ...