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的代码是这样的:

void one();
void one();
void two();
int main (){
return 0;
}

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中的:

#include "one.h"
#include "two.h"

1

2

#include "one.h"

#include "two.h"

就变成了:

// #include "one.h"
#ifndef _ONE_H_
#define _ONE_H_

void one();

#endif

// #include "two.h"
#ifndef _TWO_H_
#define _TWO_H_

// #include "one.h"
#ifndef _ONE_H_
#define _ONE_H_

void one();

#endif

void two();

#endif

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"导致的。编译预处理之后就变为了:

void one();
void two();

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 将整形变量中的数据以十六进制的形式输出。

例如:

#include <stdio.h>

int main(int argc, const char * argv[]){

int num = 0x13adf0;//加0x表示十六进制

printf("num = %x\n",num);//%x以十六进制形式打印

return 0;
}

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再将这些二进制连起来

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

打印二进制的函数:

#include <stdio.h>

//传入一个整数,打印他的二进制
void printBinary(int num){
//定义一个临时变量temp,储存位移后的数据
int temp = 0;
//定义一个临时变量temp1,储存按位与后的二进制最低位数值
int temp1 = 0;
for (int i = 0; i < 32; i++) {
//先位移,截取数据
temp = num >> (31-i);
//再与1按位与,因为任何数与1与都能得到那个任何数的二进制的最低位
temp1 = temp & 1;
//取出一位打印一位
printf("%d",temp1);
}
printf("\n");
}

int main(int argc, const char * argv[]) {

//调用函数打印出整数的二进制
printBinary(100);

return 0;
}

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代表负。其他叫数值位,数值位是这个数的绝对值的二进制位。

9的原码: 00000000 00000000 00000000 00001001

-3的原码:10000000 00000000 00000000 00000011

1

2

3

9的原码: 00000000000000000000000000001001

-3的原码:10000000000000000000000000000011

反码:

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

9的原码: 00000000 00000000 00000000 00001001

9的反码: 00000000 00000000 00000000 00001001

-3的原码:10000000 00000000 00000000 00000011

-3的反码:11111111 11111111 11111111 11111100

1

2

3

4

5

6

7

9的原码: 00000000000000000000000000001001

9的反码: 00000000000000000000000000001001

-3的原码:10000000000000000000000000000011

-3的反码:11111111111111111111111111111100

补码:

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

9的原码: 00000000 00000000 00000000 00001001

9的反码: 00000000 00000000 00000000 00001001

9的补码: 00000000 00000000 00000000 00001001

-3的原码:10000000 00000000 00000000 00000011

-3的反码:11111111 11111111 11111111 11111100

-3的补码:11111111 11111111 11111111 11111101

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

原码计算:
00000000 00000000 00000000 00000011
10000000 00000000 00000000 00000010 相减
------------------------------------
10000000 00000000 00000000 00000101 这个结果不对. 已经变成负数了.

反码计算:
00000000 00000000 00000000 00000011
11111111 11111111 11111111 11111101 相减
-------------------------------------
00000000 00000000 00000000 00000000 0 这也是错的.

补码计算:
00000000 00000000 00000000 00000011
11111111 11111111 11111111 11111110 相减
-------------------------------------
00000000 00000000 00000000 00000001 1 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.

3 & 2 ;

00000000 00000000 00000000 00000011
00000000 00000000 00000000 00000010
------------------------------------
00000000 00000000 00000000 00000010

1

2

3

4

5

6

3&2;

00000000000000000000000000000011

00000000000000000000000000000010

------------------------------------

00000000000000000000000000000010

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

3 & 1 ;
00000000 00000000 01001000 10010001
00000000 00000000 00000000 00000001
--------------------------------------
00000000 00000000 00000000 00000001

1

2

3

4

5

3&1;

00000000000000000100100010010001

00000000000000000000000000000001

--------------------------------------

00000000000000000000000000000001

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

#include <stdio.h>

int main() {

int num = 100;
//任意数按位与1,都能得到他的二进制位的最低位,如果最低位是1,则是奇数,是0则是偶数。
if (num & 1 == 0) {
printf("偶数\n");
}else{
printf("奇数\n");
}
return 0;
}

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。

3 | 2;

00000000 00000000 00000000 00000011
00000000 00000000 00000000 00000010
-------------------------------------
00000000 00000000 00000000 00000011

1

2

3

4

5

6

3|2;

00000000000000000000000000000011

00000000000000000000000000000010

-------------------------------------

00000000000000000000000000000011

按位取反  ~

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

~3;

00000000 00000000 00000000 00000011
11111111 11111111 11111111 11111100 补码
11111111 11111111 11111111 11111011 反码
10000000 00000000 00000000 00000100 -4

1

2

3

4

5

6

~3;

00000000000000000000000000000011

11111111111111111111111111111100补码

11111111111111111111111111111011反码

10000000000000000000000000000100-4

按位异或  ^

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

3 ^ 5;

00000000 000000000 00000000 00000011
00000000 000000000 00000000 00000101
----------------------------------------
00000000 000000000 00000000 00000110 +6

1

2

3

4

5

6

3^5;

000000000000000000000000000000011

000000000000000000000000000000101

----------------------------------------

000000000000000000000000000000110+6

实现交换两个变量的值:

#include <stdio.h>

int main() {

int num1 = 10,num2 = 20;
num1 = num1 ^ num2;
num2 = num1 ^ num2;
num1 = num1 ^ num2;
printf("num1 = %d,num2 = %d\n",num1,num2);
return 0;
}

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个二进制补码按位左移,就是将这个二进制位,向左移动指定的位数,溢出部分丢弃 低位补零。

3 << 2;
3的补码按位左移2位.

00000000 00000000 00000000 00000011
000000 00000000 00000000 0000001100 +12

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

按位右移  >>

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

3 >> 2;

00000000 00000000 00000000 00000011
0000000000 00000000 00000000 000000 0

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

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

时间: 2024-08-09 06:20:23

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

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

/* * 15_c语言中的进制操作.c * * Created on: 2015年7月5日 * Author: zhong */ #include <stdio.h> #include <stdlib.h> /** * c语言中的进制表示 * 前面加0b表示二进制 * 加0x表示十六进制 * 数字前加0表示八进制 * * printf按进制打印 * %d %i 以十进制打印 * %o 以八进制打印 * %x 以十六进制打印 * * %p 打印变量地址 * %f 打印小数 * %s

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

1. 什么是进制 是一种计数的方式,数值的表示形式 2. 二进制 1> 特点:只有0和1,逢2进1 2> 书写格式:0b或者0b开头 3> 使用场合:二进制指令\二进制文件,变量在内存中就是二进制存储 4> 二进制和十进制的互相转换 5> n为二进制位所能表示的数据范围(不考虑负数):0~2的n次方-1 3. 八进制 1> 特点:0~7,逢八进一 2> 书写格式:0开头 3> 八进制和二进制的互相转换 4. 十六进制 1> 特点:0~F,逢十六进一 2

C语言之进制

进制 一种计数的方式.侧重点在于计数的时候是逢多少进一. 1)      C语言可以识别的进制 二进制 每一位. 0 0 1 0 0 1 1 0 1 0 1 0 0 1 0 1 1 0 在C语言中,写一个二进制的数的方式就是在前面加一个 0b或者0B的前缀,二进制每一位是0或者1,逢2进1; 2. 八进制 每一位. 0 1 2 3 4 5 6 7 10 11 在C语言中,写一个八进制的数的方式就是在前面加一个 0的前缀,逢8进1; %o    将整型变量中得数据以八进制的形式输出 3. 十进制

C语言进制基本概念

进制:是一种计数的方式 常见的进制:十进制 二进制 八进制 十六进制 生活中都是十进制 二进制:逢二进1  书写方式以0b或者0B开头 八进制:逢八进1 书写形式以0开头  输出%o 十六进制:逢十六进1书写形式以0x开头  输出%x 结论:无论正数负数在内存中存储的都是补码 原码反码补码的概念 数据在计算机内部都是以补码的形式存储 数据分为有符号和无符号数据 无符号都正数,由十进制直接转换到二进制直接存储即可 正数的最高位是0,负数的最高位是1,对于正数: 原码 == 反码 == 补码 负数的

进制、位运算笔记

进制 位运算 进制介绍 一种计数的方式,数值的表示形式. 常见的进制有:二进制.十进制.八进制和十六进制. 二进制: 0和1,C语言中表示0b开头或者0B开头. 八进制: 0,1,2,3,4,5,6,7 C语言中以0开头的数字,例如045 十进制: 自然数 十六进制: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F C语言中以0x或者0X开头的数字 进制之间的转换: 其他进制转换成十进制的三要素: 1. 数位:数码在一个数中所处的位置. 一个序列,从右往左数位依次是0,1,2,3

JAVA学习笔记(一)--02--注释、关键字、标识符、进制等

1.注释:用于解释说明程序的文字 (1)注释的分类及格式:  A:单行注释 //  B:多行注释 /注释内容+回车/  C:文档注释 /*注释内容+回车/   (2)注释作用:  A:解释说明程序,提高程序的阅读性  B:可以帮助我们排错   2.关键字:被Java语言赋予特定含义的单词 (1)关键字特点:  组成关键字的字母全部小写  (2)关键字注意事项 A:goto和const作为保留字存在,目前并不使用  B:类似notepad++这样的高级记事本,针对关键字有特殊的颜色标记,非常直观

C语言博客(6)编程基础之进制之间的转换

在本人的C语言博客的内容中,前面两篇随笔对二进制.八进制和十六进制进行了说明,接下来讲一下不同进制之间的数字是如何转换的,这在编程中经常会用到,尤其是C语言. 其他进制向十进制转换 在C语言学习中,二进制.八进制和十六进制向十进制转换都是非常容易的,就是"按权相加". 所谓"权",也即"位权".例如,十进制第1位的位权为100=1,第2位的位权为101=10,第3位的位权为102=100:而二进制第1位的位权为20=1,第2位的位权为21=2,第

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

1 //c语言描述 将2进制转化为10进制 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #define STACK_INIT_SIZE 20 6 #define //栈满后再分配 7 8 typedef char ElemType; 9 typedef struct 10 { 11 ElemType *base; //栈底 12 ElemType *top; //栈底 13 int s

WinHex V18.7(16进制编辑器) 多国语言绿色版

软件名称: WinHex V18.7(16进制编辑器)软件语言: 简体中文授权方式: 免费试用运行环境: Win7 / Vista / Win2003 / WinXP 软件大小: 1.7MB图片预览: 软件简介:WinHex是一个非常不错的 16 进制编辑器,可以用来检查和修复各种文件.恢复删除文件.硬盘损坏造成的数据丢失等,同时它还可以让你看到其他程序隐藏起来的文件和数据 中文语言在Help菜单的Setup里面设置为Chinese即可. 软件下载页面:http://www.bkill.com/