C 語言中的關鍵字 - 數據類型、數據修飾符及邏輯結構

C 語言中有 32 個關鍵字。這是留個編譯器用的特殊字符串,用戶不可使用。web

特殊關鍵字

sizeof 和 return 是 C 語言中的兩個特殊關鍵字。svg

sizeof

sizeof 用於計算變量所佔內存空間的字節數,返回值爲 unsigned long 無符號長整型。sizeof 不依賴底層操做系統,能夠在編譯時直接獲得。函數

有兩種用法:優化

int a;
printf("%lu\n", sizeof(a));
printf("%lu\n", sizeof a);

return

return 用於執行返回操做,退出當前函數,執行函數調用棧的上一層調用者。ui

數據類型

C 語言中,各類數據類型所佔空間大小,跟具體的編譯平臺相關。例如在 32bit 機器上 int 類型佔 4Byte。this

CPU 在一個週期內所能處理數據的最優大小,就是 CPU 的位數,也是對應平臺上 int 類型的大小。spa

整型和浮點型

全部的數值類型,默認都是帶符號的。若是想使用不帶符號的數值,必須用 unsigned 關鍵字明確指定,例如 unsigned int操作系統

  • 整型類型
    char:佔 1 個字節,是最小的數據類型。有符號字符型表示範圍爲 -128~127,無符號字符型表示範圍爲 0~ 255
    short:通常佔 2 字節
    int:2 字節(16 bit CPU)或 4 字節(32 bit CPU)。有符號 int 型表示範圍爲 -32768~32767,無符號 int 型表示範圍爲 0~ 655355
    long:4 字節或 8 字節,能夠拼接 long long l 表示更大的數據。
  • 浮點類型
    float:4 字節
    double:8 字節

浮點數有多種不一樣的表示方法,雖然表示範圍很大,可是可能有精度丟失。浮點數默認是 double 類型,但能夠在浮點數末尾加個 f 來表示採用 float 類型,例如:指針

float f = 3.14 * 2; // 3.14 會分配一個 double 類型的空間
float f2 = 1.234f + 2.333f;

無符號和有符號

全部的數值類型,默認都是帶符號的。若是想使用不帶符號的數值,必須用 unsigned 關鍵字明確指定,例如 unsigned intcode

一般來講,能夠進行各類運算的數值用默認的有符號類型,而單純的數據(例如信號、二進制數據)則使用無符號的類型。

有符號數的位運算

  • 對於有符號整數,每一次右移操做採用的是sar算術右移指令,高位補充的是1
  • 對於無符號整數,每一次右移操做採用的是shr邏輯右移指令,高位補充的是0
  • 對於左移,不管是算術左移(sal)仍是邏輯左移(shl),低位補充的都是0
#include <stdio.h>

int main()
{
	char c1 = 0x80;
	unsigned char c2 = 0x80;
	printf("0x%x\t0x%x\n", c1, c2);
	int i;
	for (i = 0; i < 8; i++) {
		c1 = c1 >> 1;
		c2 = c2 >> 1;
		printf("0x%x\t0x%x\n", c1, c2);
	}
}

輸出:

0xffffff80	0x80
0xffffffc0	0x40
0xffffffe0	0x20
0xfffffff0	0x10
0xfffffff8	0x8
0xfffffffc	0x4
0xfffffffe	0x2
0xffffffff	0x1
0xffffffff	0x0

void 類型

void 至關於一個佔位符,能夠聲明變量或返回值,可是void 類型的變量不可直接使用,須要強制轉換爲其餘類型才能夠。

void a;
void fun();

void 一般用於:

  • 對函數返回的限定
  • 對函數參數的限定

溢出

每種數據類型在存儲數據時,都有範圍限制。若是把超過限制的數據存入某個變量,會致使各類異常情況。編譯時會有警告。

char c = 666;
printf("%d", c);

輸出:

/code/main.c: In function ‘main’:
/code/main.c:5:1: warning: overflow in implicit constant conversion [-Woverflow]
char c = 666;
 ^
-102

自定義數據類型

struct、union、enum 是 3 種自定義的數據類型,typedef 是爲數據類型起一個別名。

自定義數據類型,就是把已有的數據類型進行組合,獲得一個匹配實際的資源類型的存儲類型。

使用自定義數據類型時,必須在變量前指明這個變量是哪個數據類型,例如 struct MyStruct s;

struct 結構體

struct 結構體就是變量的集合,把已有的類型組合到一塊兒,造成新的類型的語句。struct 中的變量按照順序存儲。

struct 也是一條語句,定義時必須以分號結尾。使用時必須用 struct 自定義的名稱 變量名 的形式來聲明變量,示例:

#include <stdio.h>

struct People {
	unsigned int age;
	char* name;
}; // 這裏必須加分號

int main()
{
	struct People s = {20, "jack"};
	printf("%d, %s", s.age, s.name);
}

union 共用體

union 共用體中,全部變量共享同一塊內存。由於內存的起始地址重合,任什麼時候刻都只能存儲一個變量。

#include <stdio.h>

union myUnion {
	unsigned int i;
	char c;
}; // 這裏必須加分號

int main()
{
	union myUnion s;
	s.i = 666;
	printf("%d", s.i);// s 中只有 i 一個元素,若是打印 c 會報錯
	s.c = 'a';
	printf("%c", s.c);// s 中只有 c 一個元素,若是打印 i 會報錯
}

輸出爲:``666a

enum 枚舉

C 語言中能用 enum 實現的代碼,均可以不用 enum 實現。

enum 是常量的集合。例如一週的七天,能夠用 #define 或 const int 來定義,也能夠打包放到 enum 中。enum 特色是:

  • enum 中首元素默認是 0,能夠指定爲任意 int 類型的整數,後序全部元素依次加一。
  • enum 枚舉類型能夠不指定名稱,由於 enum 中的每個元素均可以當作全局常量直接使用

下面示例中的三種寫法等價,用法是同樣的:

#include <stdio.h>

/* #define SUN 7 #define MON 1 #define TUE 2 const int SUN = 7; const int MON = 1; const int TUE = 2; */

enum {SUN = 0, MON, TUE}; // 默認第一個元素是0,後序元素依次加一

int main()
{
	printf("%d\n", TUE);
}

typedef

typedef 爲已有的數據類型起別名,可讓程序可讀性更高。一般在 Linux 內核源碼中,用 typedef 起的別名,後綴都是 _t

#include <stdio.h>

typedef unsigned int uint_t;

int main()
{
	uint_t a = 666;
	printf("%d", a);
	return 0;
}

邏輯結構

分支語句

if else 語句

if (3 < 4)
{//...}

switch case default 語句

語法:

switch(整型變量)
{
	case 整型數字:
		// 執行語句
		break; // 必須加,不然會向下執行
	default:
		// 上面沒有匹配到時,默認執行這裏的語句
}
#include <stdio.h>

int main()
{
	int i;
	for (i = 0; i < 5; i++)
	{
		switch (i/3)
		{
			case 0:
				printf("%d\n", i);
			case 1:
				printf("%d\n", i);
			case 2:
				printf("%d\n", i);
				break;
			default:
				printf("this is default\n");
		}
	}
}

由於沒加 break 會致使 switch case 貫穿,輸出以下:

0
0
0
1
1
1
2
2
2
3
3
4
4

循環語句

for 循環

跟次數相關。

C 語言中,for 循環的初始化語句中,必須用已經聲明過的變量,比較差:

int i;
for (i = 0; i < 10; i++)
{//...}

do while 循環

至少執行一次。

int a = 666;
do {
	printf("%d", a);
} while (a++ < 0);

while 循環

跟條件相關。

continue、break、goto 語句

continue:結束本次循環,開始下次循環
break:結束語句所在的循環
goto:跳轉到指定語句位置

類型修飾符

變量的數據類型定義以後,變量所佔用的存儲空間大小就固定了。變量的具體存儲位置,就須要用類型修飾符來控制。默認的類型是 auto,int a 等價於 auto int a

  • auto:變量默認的修飾符,存儲在普通內存中。經過地址來尋址,能夠用 & 查看具體地址。
  • register:變量存儲在 CPU 內部的寄存器中,速度快,容量小。& 取地址符號對這種變量無效。變量訪問頻率很高時,才考慮放在寄存器中。編譯器會盡可能把變量放在寄存器中,但若是寄存器不足,則變量仍是會放在內存中。一般每一個寄存器都有特殊名字,例如 ARM 的 R0,R1 等。
  • static:有 3 中使用場景
    • 修飾函數內變量:static int a;
    • 修飾函數外變量:
    • 修飾函數:static int fun(){}
  • const:常量定義。其實是隻讀變量,仍是有辦法修改(藉助指針)。
  • extern:外部聲明,表示函數或變量在外部文件中
  • volatile:告訴編譯器,不優化編譯。部分變量不只軟件能夠修改,外部硬件也能夠修改,編譯器此時的優化可能致使錯誤。
相關文章
相關標籤/搜索