學習目標
1.【掌握】include預處理指令web
2.【掌握】多文件開發數組
3.【瞭解】認識進制編輯器
4.【掌握】進制之間的互相轉換ide
5.【掌握】原碼,反碼,補碼函數
6.【掌握】位運算學習
7.【掌握】int類型的修飾符spa
1、include預處理指令
其實咱們早就有接觸文件包含這個指令了, 就是#include,它能夠將一個文件的所有內容拷貝另外一個文件中。操作系統
使用語法:3d
第一種:#include <文件名>code
直接到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
|
void
one
(
)
;
void
one
(
)
;
void
two
(
)
;
int
main
(
)
{
return
0
;
}
|
第1行是由#include "one.h"致使的,第二、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_
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
|
第2~第7行是#include "one.h"致使的,第10~第23行是#include "two.h"致使的。編譯預處理以後就變爲了:
1
2
|
void
one
(
)
;
void
two
(
)
;
|
這纔是咱們想要的結果
2、多文件開發
你們都知道咱們的C程序是由1個1個的函數組成的,當咱們的程序很大的時候,將這些函數代碼寫在寫在同1個文件之中是絕對不科學。函數太多,不方便管理,而且不利於團隊開發。
咱們的程序實際上都是分爲1個1個的模塊的,不管多大的程序都是由1個1個的小功能組成的。模塊就是功能相同或者類似的一些函數。在實際開發中,不一樣的人負責開發不一樣的功能模塊,要使用模塊中的功能的話,直接調用就能夠了。
如何寫模塊?
寫模塊的人,通常狀況下要寫兩個文件。.c文件 .h文件. header 頭文件。
.h文件之中,寫上函數的聲明。
.c文件之中,寫上函數的實現。
想要調用模塊之中的函數,只須要包含這個模塊的頭文件就能夠了。好比咱們使用printf函數須要包含stdio.h頭文件同樣,只要包含了函數的聲明,咱們就能直接使用函數了。
例如:
咱們還能給函數分組,例如:
右鍵,選擇New Group能夠建立組,進行源文件分組管理。放在組裏的源文件其實他的路徑是不會改變的:
3、認識進制
什麼是進制?
進制是記數的一種方式,側重點在於記數的時候,是逢多少進一。好比咱們平常生活中用的十進制,逢10進1。C語言中也有進制,C語言能識別的進制有二進制,十進制,八進制,十六進制。多少多少進制就是逢多少進1。
二進制:
逢二進一,每1位用0和1表示。
在C語言的代碼中,若是要寫1個二進制的數,那麼就必需要在這個二進制的數的前面加1個0b的前綴。
C語言沒有提供1個個是控制符來將1個整形變量中的數據以二進制的形式輸出。
八進制:
逢八進一,每1位 0、一、二、三、四、五、六、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>
int
main
(
int
argc
,
const
char
*
argv
[
]
)
{
int
num
=
0x13adf0
;
//加0x表示十六進制
printf
(
"num = %x\n"
,
num
)
;
//%x以十六進制形式打印
return
0
;
}
|
4、進制直接的互相轉換
咱們先來引入一個概念,固然,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>
//傳入一個整數,打印他的二進制
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
;
}
|
本身隨意寫的,網上還有不少功能更多的進制轉換函數,須要的本身去谷歌吧。
5、原碼,反碼,補碼
聲明1個變量,其實就是在內存之中申請指定字節數的空間,用來存儲數據。不管任何數據在內存之中都是以其二進制的形式存儲的,而且是以這個數據的二進制的補碼的形式存儲的。那什麼是補碼呢?原碼、反碼、補碼 都是二進制,只不過是二進制的不一樣的表現形式。
強調:全部的數據都是以其二進制的補碼的形式存儲在內存之中的。
原碼:
最高位用來表示符號位,0表明正,1表明負。其餘叫數值位,數值位是這個數的絕對值的二進制位。
1
2
3
|
9的原碼:
00000000
00000000
00000000
00001001
-
3的原碼:
10000000
00000000
00000000
00000011
|
反碼:
正數的反碼就是其原碼。負數的反碼,是在其原碼的基礎之上,符號位不變,數值位取反。
1
2
3
4
5
6
7
|
9的原碼:
00000000
00000000
00000000
00001001
9的反碼:
00000000
00000000
00000000
00001001
-
3的原碼:
10000000
00000000
00000000
00000011
-
3的反碼:
11111111
11111111
11111111
11111100
|
補碼:
正數的補碼就是,其原碼。負數的補碼,是在其反碼的基礎之上加1。
1
2
3
4
5
6
7
8
9
10
11
|
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
|
爲何要用補碼來儲存數據,由於計算機之中只有加法,沒有減法。爲了更低成本的計算出結果,因此使用補碼來存儲數據。以下例子:3 + (-2) = 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
原碼計算
:
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結果是對
.
|
6、位運算
什麼叫作位運算?
1個二進制數的每1位來參與運算,參與位運算的前提,是這個數必須是二進制數。而且參與運算的二進制數據必須是補碼的形式,而且算出來的結果也是補碼。
按位與 &
指的是兩個數的二進制的補碼 按位進行與運算. 若是都爲1 結果就爲1 不然就爲0.
1
2
3
4
5
6
|
3
&
2
;
00000000
00000000
00000000
00000011
00000000
00000000
00000000
00000010
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
00000000
00000000
00000000
00000010
|
注意:任何數按位與1,結果是這個數的最低位
1
2
3
4
5
|
3
&
1
;
00000000
00000000
01001000
10010001
00000000
00000000
00000000
00000001
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
00000000
00000000
00000000
00000001
|
偶數的最低位必定是0,奇數的最低位必定是1。用1個數去按位與1,若是結果爲0那麼這個數必定是1個偶數,若是結果爲1,那麼這個數必定是1個奇數。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#include <stdio.h>
int
main
(
)
{
int
num
=
100
;
//任意數按位與1,都能獲得他的二進制位的最低位,若是最低位是1,則是奇數,是0則是偶數。
if
(
num
&
1
==
0
)
{
printf
(
"偶數\n"
)
;
}
else
{
printf
(
"奇數\n"
)
;
}
return
0
;
}
|
按位或 |
參與按位或的二進制補碼,只要有1位爲1,那麼結果就爲1,只有都爲0的時候才爲0。
1
2
3
4
5
6
|
3
|
2
;
00000000
00000000
00000000
00000011
00000000
00000000
00000000
00000010
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
-
00000000
00000000
00000000
00000011
|
按位取反 ~
這是1個單目運算符,只須要1個數據參與,將1變0,0變1
1
2
3
4
5
6
|
~
3
;
00000000
00000000
00000000
00000011
11111111
11111111
11111111
11111100補碼
11111111
11111111
11111111
11111011反碼
10000000
00000000
00000000
00000100
-
4
|
按位異或 ^
參與按位異或的二進制補碼,每一位,相同爲0,不一樣爲1。
1
2
3
4
5
6
|
3
^
5
;
00000000
000000000
00000000
00000011
00000000
000000000
00000000
00000101
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
00000000
000000000
00000000
00000110
+
6
|
實現交換兩個變量的值:
1
2
3
4
5
6
7
8
9
10
11
|
#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個二進制補碼按位左移,就是將這個二進制位,向左移動指定的位數,溢出部分丟棄 低位補零。
1
2
3
4
5
|
3
<<
2
;
3的補碼按位左移
2位
.
00000000
00000000
00000000
00000011
000000
00000000
00000000
0000001100
+
12
|
注意:
1個數按位左移,有可能改變其正負性。
1個數按位左移n位,至關於這個數乘以2的n次方。
16 << 3; 至關於16 * 2的3次方。就是16*8=128
按位右移 >>
參與按位右移的二進制的補碼,向右移動指定的位數,溢出部分補齊,高位補符號位。
1
2
3
4
|
3
>>
2
;
00000000
00000000
00000000
00000011
0000000000
00000000
00000000
000000
0
|
注意:
1一個數按位右移,不會改變1個數的正負性。
1個數按位右移n位,至關於這個數除以2的n次方。
6、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
要求變量的最高位用來表示符號位,默認就是這樣的。因此這個關鍵詞通常沒啥用。