進制基本概念
-
什么是進制?
- 進制是一種計數的方式,數值的表示形式
-
常見的進制
- 十進制、二進制、八進制、十六進制
-
進制書寫的格式和規律
- 十進制 0、1、2、3、4、5、6、7、8、9 逢十進一
- 二進制 0、1 逢二進一
- 書寫形式:需要以0b或者0B開頭,例如: 0b101
- 八進制 0、1、2、3、4、5、6、7 逢八進一
- 書寫形式:在前面加個0,例如: 061
- 十六進制 0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F 逢十六進一
- 書寫形式:在前面加個0x或者0X,例如: 0x45
-
練習
- 1.用不同進制表示如下有多少個方格
- 2.判斷下列數字是否合理
00011 0x001 0x7h4 10.98 0986 .089-109 +178 0b325 0b0010 0xffdc 96f 96.0f 96.oF -.003
進制轉換
- 10 進制轉 2 進制
- 除2取余, 余數倒序; 得到的序列就是二進制表示形式
- 例如: 將十進制(97) 10轉換為二進制數
- 2 進制轉 10 進制
- 每一位二進制進制位的值 * 2的當前索引次冪; 再將所有位求出的值相加
- 例如: 將二進制01100100轉換為十進制
01100100 索引從右至左, 從零開始 第0位: 0 * 2^0 = 0; 第1位: 0 * 2^1 = 0; 第2位: 1 * 2^2 = 4; 第3位: 0 * 2^3 = 0; 第4位: 0 * 2^4 = 0; 第5位: 1 * 2^5 = 32; 第6位: 1 * 2^6 = 64; 第7位: 0 * 2^7 = 0; 最終結果為: 0 + 0 + 4 + 0 + 0 + 32 + 64 + 0 = 100
- 2 進制轉 8 進制
- 三個二進制位代表一個八進制位, 因為3個二進制位的最大值是7,而八進制是逢8進1
- 例如: 將二進制01100100轉換為八進制數
從右至左每3位劃分為8進制的1位, 不夠前面補0 001 100 100 第0位: 100 等于十進制 4 第1位: 100 等于十進制 4 第2位: 001 等于十進制 1 最終結果: 144就是轉換為8進制的值
- 2 進制轉 16 進制
- 四個二進制位代表一個十六進制位,因為4個二進制位的最大值是15,而十六進制是逢16進1
- 例如: 將二進制01100100轉換為十六進制數
從右至左每4位劃分為16進制的1位, 不夠前面補0 0110 0100 第0位: 0100 等于十進制 4 第1位: 0110 等于十進制 6 最終結果: 64就是轉換為16進制的值
- 其它進制轉換為十進制
- 系數 * 基數 ^ 索引 之和
十進制 --> 十進制 12345 = 10000 + 2000 + 300 + 40 + 5 = (1 * 10 ^ 4) + (2 * 10 ^ 3) + (3 * 10 ^ 2) + (4 * 10 ^ 1) + (5 * 10 ^ 0) = (1 * 10000) + (2 + 1000) + (3 * 100) + (4 * 10) + (5 * 1) = 10000 + 2000 + 300 + 40 + 5 = 12345 規律: 其它進制轉換為十進制的結果 = 系數 * 基數 ^ 索引 之和 系數: 每一位的值就是一個系數 基數: 從x進制轉換到十進制, 那么x就是基數 索引: 從最低位以0開始, 遞增的數
二進制 --> 十進制 543210 101101 = (1 * 2 ^ 5) + (0 * 2 ^ 4) + (1 * 2 ^ 3) + (1 * 2 ^ 2) + (0 * 2 ^ 1) + (1 * 2 ^ 0) = 32 + 0 + 8 + 4 + 0 + 1 = 45 八進制 --> 十進制 016 = (0 * 8 ^ 2) + (1 * 8 ^ 1) + (6 * 8 ^ 0) = 0 + 8 + 6 = 14 十六進制 --> 十進制 0x11f = (1 * 16 ^ 2) + (1 * 16 ^ 1) + (15 * 16 ^ 0) = 256 + 16 + 15 = 287
- 十進制快速轉換為其它進制
- 十進制除以
基數
取余, 倒敘讀取
十進制 --> 二進制 100 --> 1100100 100 / 2 = 50 0 50 / 2 = 25 0 25 / 2 = 12 1 12 / 2 = 6 0 6 / 2 = 3 0 3 / 2 = 1 1 1 / 2 = 0 1 十進制 --> 八進制 100 --> 144 100 / 8 = 12 4 12 / 8 = 1 4 1 / 8 = 0 1 十進制 --> 十六進制 100 --> 64 100 / 16 = 6 4 6 / 16 = 0 6
- 十進制除以
十進制小數轉換為二進制小數
- 整數部分,直接轉換為二進制即可
- 小數部分,使用"乘2取整,順序排列"
- 用2乘十進制小數,可以得到積,將積的整數部分取出,再用2乘余下的小數部分,直到積中的小數部分為零,或者達到所要求的精度為止
- 然后把取出的整數部分按順序排列起來, 即是小數部分二進制
- 最后將整數部分的二進制和小數部分的二進制合并起來, 即是一個二進制小數
- 例如: 將12.125轉換為二進制
// 整數部分(除2取余)
12
/ 2
------
6 // 余0
/ 2
------
3 // 余0
/ 2
------
1 // 余1
/ 2
------
0 // 余1
//12 --> 1100
// 小數部分(乘2取整數積)
0.125
* 2
------
0.25 //0
0.25
* 2
------
0.5 //0
0.5
* 2
------
1.0 //1
0.0
// 0.125 --> 0.001
// 12.8125 --> 1100.001
二進制小數轉換為十進制小數
- 整數部分按照二進制轉十進制即可
- 小數部分從最高位開始乘以2的負n次方, n從1開始
- 例如: 將 1100.001轉換為十進制
// 整數部分(乘以2的n次方, n從0開始)
0 * 2^0 = 0
0 * 2^1 = 0
1 * 2^2 = 4
1 * 2^3 = 8
// 1100 == 8 + 4 + 0 + 0 == 12
// 小數部分(乘以2的負n次方, n從0開始)
0 * (1/2) = 0
0 * (1/4) = 0
1 * (1/8) = 0.125
// .100 == 0 + 0 + 0.125 == 0.125
// 1100.001 --> 12.125
- 練習:
- 將0.8125轉換為二進制
- 將0.1101轉換為十進制
0.8125
* 2
--------
1.625 // 1
0.625
* 2
--------
1.25 // 1
0.25
* 2
--------
0.5 // 0
* 2
--------
1.0 // 1
0.0
// 0. 8125 --> 0.1101
1*(1/2) = 0.5
1*(1/4)=0.25
0*(1/8)=0
1*(1/16)=0.0625
//0.1101 --> 0.5 + 0.25 + 0 + 0.0625 == 0.8125
原碼反碼補碼
- 計算機只能識別0和1, 所以計算機中存儲的數據都是以0和1的形式存儲的
- 數據在計算機內部是以補碼的形式儲存的, 所有數據的運算都是以補碼進行的
- 正數的原碼、反碼和補碼
- 正數的原碼、反碼和補碼都是它的二進制
- 例如: 12的原碼、反碼和補碼分別為
0000 0000 0000 0000 0000 0000 0000 1100
0000 0000 0000 0000 0000 0000 0000 1100
0000 0000 0000 0000 0000 0000 0000 1100
- 負數的原碼、反碼和補碼
- 二進制的最高位我們稱之為符號位, 最高位是0代表是一個正數, 最高位是1代表是一個負數
- 一個負數的原碼, 是將該負數的二進制最高位變為1
- 一個負數的反碼, 是將該數的原碼
除了符號位
以外的其它位取反 - 一個負數的補碼, 就是它的反碼 + 1
- 例如: -12的原碼、反碼和補碼分別為
0000 0000 0000 0000 0000 0000 0000 1100 // 12二進制 1000 0000 0000 0000 0000 0000 0000 1100 // -12原碼 1111 1111 1111 1111 1111 1111 1111 0011 // -12反碼 1111 1111 1111 1111 1111 1111 1111 0100 // -12補碼
- 負數的原碼、反碼和補碼逆向轉換
- 反碼 = 補碼-1
- 原碼= 反碼最高位不變, 其它位取反
1111 1111 1111 1111 1111 1111 1111 0100 // -12補碼 1111 1111 1111 1111 1111 1111 1111 0011 // -12反碼 1000 0000 0000 0000 0000 0000 0000 1100 // -12原碼
- 為什么要引入反碼和補碼
- 在學習本節內容之前,大家必須明白一個東西, 就是計算機只能做加法運算, 不能做減法和乘除法, 所以的減法和乘除法內部都是用加法來實現的
- 例如: 1 - 1, 內部其實就是 1 + (-1);
- 例如: 3 * 3, 內部其實就是 3 + 3 + 3;
- 例如: 9 / 3, 內部其實就是 9 + (-3) + (-3) + (-3);
- 首先我們先來觀察一下,如果只有原碼會存儲什么問題
- 很明顯, 通過我們的觀察, 如果只有原碼, 1-1的結果不對
// 1 + 1 0000 0000 0000 0000 0000 0000 0000 0001 // 1原碼 +0000 0000 0000 0000 0000 0000 0000 0001 // 1原碼 --------------------------------------- 0000 0000 0000 0000 0000 0000 0000 0010 == 2 // 1 - 1; 1 + (-1); 0000 0000 0000 0000 0000 0000 0000 0001 // 1原碼 +1000 0000 0000 0000 0000 0000 0000 0001 // -1原碼 --------------------------------------- 1000 0000 0000 0000 0000 0000 0000 0010 == -2
- 在學習本節內容之前,大家必須明白一個東西, 就是計算機只能做加法運算, 不能做減法和乘除法, 所以的減法和乘除法內部都是用加法來實現的
-
- 正是因為對于減法來說,如果使用原碼結果是不正確的, 所以才引入了反碼
- 通過反碼計算減法的結果, 得到的也是一個反碼;
- 將計算的結果符號位不變其余位取反,就得到了計算結果的原碼
- 通過對原碼的轉換, 很明顯我們計算的結果是-0, 符合我們的預期
// 1 - 1; 1 + (-1); 0000 0000 0000 0000 0000 0000 0000 0001 // 1反碼 1111 1111 1111 1111 1111 1111 1111 1110 // -1反碼 --------------------------------------- 1111 1111 1111 1111 1111 1111 1111 1111 // 計算結果反碼 1000 0000 0000 0000 0000 0000 0000 0000 // 計算結果原碼 == -0
- 正是因為對于減法來說,如果使用原碼結果是不正確的, 所以才引入了反碼
-
- 雖然反碼能夠滿足我們的需求, 但是對于0來說, 前面的負號沒有任何意義, 所以才引入了補碼
- 由于int只能存儲4個字節, 也就是32位數據, 而計算的結果又33位, 所以最高位溢出了,符號位變成了0, 所以最終得到的結果是0
// 1 - 1; 1 + (-1); 0000 0000 0000 0000 0000 0000 0000 0001 // 1補碼 1111 1111 1111 1111 1111 1111 1111 1111 // -1補碼 --------------------------------------- 10000 0000 0000 0000 0000 0000 0000 0000 // 計算結果補碼 0000 0000 0000 0000 0000 0000 0000 0000 // == 0
- 雖然反碼能夠滿足我們的需求, 但是對于0來說, 前面的負號沒有任何意義, 所以才引入了補碼
位運算符
- 程序中的所有數據在計算機內存中都是以二進制的形式儲存的。
- 位運算就是直接對整數在內存中的二進制位進行操作
- C語言提供了6個位操作運算符, 這些運算符只能用于整型操作數
符號 | 名稱 | 運算結果 |
---|---|---|
& | 按位與 | 同1為1 |
| | 按位或 | 有1為1 |
^ | 按位異或 | 不同為1 |
~ | 按位取反 | 0變1,1變0 |
<< | 按位左移 | 乘以2的n次方 |
>> | 按位右移 | 除以2的n次方 |
- 按位與:
- 只有對應的兩個二進位均為1時,結果位才為1,否則為0
- 規律: 二進制中,與1相&就保持原位,與0相&就為0
9&5 = 1
1001
&0101
------
0001
- 按位或:
- 只要對應的二個二進位有一個為1時,結果位就為1,否則為0
9|5 = 13
1001
|0101
------
1101
- 按位異或
- 當對應的二進位相異(不相同)時,結果為1,否則為0
- 規律:
- 相同整數相的結果是0。比如55=0
- 多個整數相^的結果跟順序無關。例如: 567=576
- 同一個數異或另外一個數兩次, 結果還是那個數。例如: 577 = 5
9^5 = 12
1001
^0101
------
1100
- 按位取反
- 各二進位進行取反(0變1,1變0)
~9 =-10
0000 0000 0000 0000 0000 1001 // 取反前
1111 1111 1111 1111 1111 0110 // 取反后
// 根據負數補碼得出結果
1111 1111 1111 1111 1111 0110 // 補碼
1111 1111 1111 1111 1111 0101 // 反碼
1000 0000 0000 0000 0000 1010 // 源碼 == -10
- 位運算應用場景:
- 判斷奇偶(按位或)
偶數: 的二進制是以0結尾 8 -> 1000 10 -> 1010 奇數: 的二進制是以1結尾 9 -> 1001 11 -> 1011 任何數和1進行&操作,得到這個數的最低位 1000 &0001 ----- 0000 // 結果為0, 代表是偶數 1011 &0001 ----- 0001 // 結果為1, 代表是奇數
- 權限系統
enum Unix { S_IRUSR = 256,// 100000000 用戶可讀 S_IWUSR = 128,// 10000000 用戶可寫 S_IXUSR = 64,// 1000000 用戶可執行 S_IRGRP = 32,// 100000 組可讀 S_IWGRP = 16,// 10000 組可寫 S_IXGRP = 8,// 1000 組可執行 S_IROTH = 4,// 100 其它可讀 S_IWOTH = 2,// 10 其它可寫 S_IXOTH = 1 // 1 其它可執行 }; // 假設設置用戶權限為可讀可寫 printf("%d\n", S_IRUSR | S_IWUSR); // 384 // 110000000
- 交換兩個數的值(按位異或)
a = a^b; b = b^a; a = a^b;
- 按位左移
- 把整數a的各二進位全部左移n位,高位丟棄,低位補0
- 由于左移是丟棄最高位,0補最低位,所以符號位也會被丟棄,左移出來的結果值可能會改變正負性
- 規律: 左移n位其實就是乘以2的n次方
- 把整數a的各二進位全部左移n位,高位丟棄,低位補0
2<<1; //相當于 2 *= 2 // 4
0010
<<0100
2<<2; //相當于 2 *= 2^2; // 8
0010
<<1000
- 按位右移
- 把整數a的各二進位全部右移n位,保持符號位不變
- 為正數時, 符號位為0,最高位補0
- 為負數時,符號位為1,最高位是補0或是補1(取決于編譯系統的規定)
- 規律: 快速計算一個數除以2的n次方
- 把整數a的各二進位全部右移n位,保持符號位不變
2>>1; //相當于 2 /= 2 // 1
0010
>>0001
4>>2; //相當于 4 /= 2^2 // 1
0100
>>0001
- 練習:
- 寫一個函數把一個10進制數按照二進制格式輸出
#include <stdio.h>
void printBinary(int num);
int main(int argc, const char * argv[]) {
printBinary(13);
}
void printBinary(int num){
int len = sizeof(int)*8;
int temp;
for (int i=0; i<len; i++) {
temp = num; //每次都在原數的基礎上進行移位運算
temp = temp>>(31-i); //每次移動的位數
int t = temp&1; //取出最后一位
if(i!=0&&i%4==0)printf(" "); printf("%d",t);
}
}
變量內存分析
- 內存模型
- 內存模型是線性的(有序的)
- 對于 32 機而言,最大的內存地址是2^32次方bit(4294967296)(4GB)
- 對于 64 機而言,最大的內存地址是2^64次方bit(18446744073709552000)(171億GB)
- CPU 讀寫內存
- CPU 在運作時要明確三件事
- 存儲單元的地址(地址信息)
- 器件的選擇,讀 or 寫 (控制信息)
- 讀寫的數據 (數據信息)
- CPU 在運作時要明確三件事
- 如何明確這三件事情
- 通過地址總線找到存儲單元的地址
- 通過控制總線發送內存讀寫指令
- 通過數據總線傳輸需要讀寫的數據
- 地址總線: 地址總線寬度決定了CPU可以訪問的物理地址空間(尋址能力)
- 例如: 地址總線的寬度是1位, 那么表示可以訪問 0 和 1的內存
- 例如: 地址總線的位數是2位, 那么表示可以訪問 00、01、10、11的內存
- 數據總線: 數據總線的位數決定CPU單次通信能交換的信息數量
- 例如: 數據總線:的寬度是1位, 那么一次可以傳輸1位二進制數據
- 例如: 地址總線的位數是2位,那么一次可以傳輸2位二進制數據
- 控制總線: 用來傳送各種控制信號
- 寫入流程
- CPU 通過地址線將找到地址為 FFFFFFFB 的內存
- CPU 通過控制線發出內存寫入命令,選中存儲器芯片,并通知它,要其寫入數據。
-
CPU 通過數據線將數據 8 送入內存 FFFFFFFB 單元中
- 讀取流程
- CPU 通過地址線將找到地址為 FFFFFFFB 的內存
- CPU 通過控制線發出內存讀取命令,選中存儲器芯片,并通知它,將要從中讀取數據
-
存儲器將 FFFFFFFB 號單元中的數據 8 通過數據線送入 CPU寄存器中
- 變量的存儲原則
- 先分配字節地址大內存,然后分配字節地址小的內存(內存尋址是由大到小)
- 變量的首地址,是變量所占存儲空間字節地址(最小的那個地址 )
- 低位保存在低地址字節上,高位保存在高地址字節上
10的二進制: 0b00000000 00000000 00000000 00001010 高字節← →低字節
char類型內存存儲細節
- char類型基本概念
- char是C語言中比較靈活的一種數據類型,稱為“字符型”
- char類型變量占1個字節存儲空間,共8位
- 除單個字符以外, C語言的的轉義字符也可以利用char類型存儲
字符 | 意義 |
---|---|
\b | 退格(BS)當前位置向后回退一個字符 |
\r | 回車(CR),將當前位置移至本行開頭 |
\n | 換行(LF),將當前位置移至下一行開頭 |
\t | 水平制表(HT),跳到下一個 TAB 位置 |
\0 | 用于表示字符串的結束標記 |
\ |
代表一個反斜線字符 \ |
\" | 代表一個雙引號字符" |
\' | 代表一個單引號字符' |
- char型數據存儲原理
- 計算機只能識別0和1, 所以char類型存儲數據并不是存儲一個字符, 而是將字符轉換為0和1之后再存儲
- 正是因為存儲字符類型時需要將字符轉換為0和1, 所以為了統一, 老美就定義了一個叫做ASCII表的東東
-
ASCII表中定義了每一個字符對應的整數
char ch1 = 'a';
printf("%i\n", ch1); // 97
char ch2 = 97;
printf("%c\n", ch2); // a
- char類型注意點
- char類型占一個字節, 一個中文字符占3字節(unicode表),所有char不可以存儲中文
char c = '我'; // 錯誤寫法
- 除轉義字符以外, 不支持多個字符
char ch = 'ab'; // 錯誤寫法
- char類型存儲字符時會先查找對應的ASCII碼值, 存儲的是ASCII值, 所以字符6和數字6存儲的內容不同
char ch1 = '6'; // 存儲的是ASCII碼 64 char ch2 = 6; // 存儲的是數字 6
- 練習
- 定義一個函數, 實現輸入一個小寫字母,要求轉換成大寫輸出
類型說明符
- 類型說明符基本概念
- C語言提供了說明長度和說明符號位的兩種類型說明符, 這兩種類型說明符一共有4個:
- short 短整型 (說明長度)
- long 長整型 (說明長度)
- signed 有符號型 (說明符號位)
- unsigned 無符號型 (說明符號位)
- C語言提供了說明長度和說明符號位的兩種類型說明符, 這兩種類型說明符一共有4個:
- 這些說明符一般都是用來修飾int類型的,所以在使用時可以省略int
- 這些說明符都屬于C語言關鍵字
short和long
- short和long可以提供不同長度的整型數,也就是可以改變整型數的取值范圍。
- 在64bit編譯器環境下,int占用4個字節(32bit),取值范圍是-2^31 ~ 2^31-1;
- short占用2個字節(16bit),取值范圍是-2^15 ~ 2^15-1;
- long占用8個字節(64bit),取值范圍是-2^63 ~ 2^63-1
- 總結一下:在64位編譯器環境下:
- short占2個字節(16位)
- int占4個字節(32位)
- long占8個字節(64位)。
- 因此,如果使用的整數不是很大的話,可以使用short代替int,這樣的話,更節省內存開銷。
- 世界上的編譯器林林總總,不同編譯器環境下,int、short、long的取值范圍和占用的長度又是不一樣的。比如在16bit編譯器環境下,long只占用4個字節。不過幸運的是,ANSI \ ISO制定了以下規則:
- short跟int至少為16位(2字節)
- long至少為32位(4字節)
- short的長度不能大于int,int的長度不能大于long
- char一定為為8位(1字節),畢竟char是我們編程能用的最小數據類型
- 可以連續使用2個long,也就是long long。一般來說,long long的范圍是不小于long的,比如在32bit編譯器環境下,long long占用8個字節,long占用4個字節。不過在64bit編譯器環境下,long long跟long是一樣的,都占用8個字節。
#include <stdio.h>
int main()
{
// char占1個字節, char的取值范圍 -2^7~2^7
char num = 129;
printf("size = %i\n", sizeof(num)); // 1
printf("num = %i\n", num); // -127
// short int 占2個字節, short int的取值范圍 -2^15~2^15-1
short int num1 = 32769;// -32767
printf("size = %i\n", sizeof(num1)); // 2
printf("num1 = %hi\n", num1);
// int占4個字節, int的取值范圍 -2^31~2^31-1
int num2 = 12345678901;
printf("size = %i\n", sizeof(num2)); // 4
printf("num2 = %i\n", num2);
// long在32位占4個字節, 在64位占8個字節
long int num3 = 12345678901;
printf("size = %i\n", sizeof(num3)); // 4或8
printf("num3 = %ld\n", num3);
// long在32位占8個字節, 在64位占8個字節 -2^63~2^63-1
long long int num4 = 12345678901;
printf("size = %i\n", sizeof(num4)); // 8
printf("num4 = %lld\n", num4);
// 由于short/long/long long一般都是用于修飾int, 所以int可以省略
short num5 = 123;
printf("num5 = %lld\n", num5);
long num6 = 123;
printf("num6 = %lld\n", num6);
long long num7 = 123;
printf("num7 = %lld\n", num7);
return 0;
}
signed和unsigned
- 首先要明確的:signed int等價于signed,unsigned int等價于unsigned
- signed和unsigned的區別就是它們的最高位是否要當做符號位,并不會像short和long那樣改變數據的長度,即所占的字節數。
- signed:表示有符號,也就是說最高位要當做符號位。但是int的最高位本來就是符號位,因此signed和int是一樣的,signed等價于signed int,也等價于int。signed的取值范圍是-2^31 ~ 2^31 - 1
- unsigned:表示無符號,也就是說最高位并不當做符號位,所以不包括負數。
- 因此unsigned的取值范圍是:0000 0000 0000 0000 0000 0000 0000 0000 ~ 1111 1111 1111 1111 1111 1111 1111 1111,也就是0 ~ 2^32 - 1
#include <stdio.h>
int main()
{
// 1.默認情況下所有類型都是由符號的
int num1 = 9;
int num2 = -9;
int num3 = 0;
printf("num1 = %i\n", num1);
printf("num2 = %i\n", num2);
printf("num3 = %i\n", num3);
// 2.signed用于明確說明, 當前保存的數據可以是有符號的, 一般情況下很少使用
signed int num4 = 9;
signed int num5 = -9;
signed int num6 = 0;
printf("num4 = %i\n", num4);
printf("num5 = %i\n", num5);
printf("num6 = %i\n", num6);
// signed也可以省略數據類型, 但是不推薦這樣編寫
signed num7 = 9;
printf("num7 = %i\n", num7);
// 3.unsigned用于明確說明, 當前不能保存有符號的值, 只能保存0和正數
// 應用場景: 保存銀行存款,學生分數等不能是負數的情況
unsigned int num8 = -9;
unsigned int num9 = 0;
unsigned int num10 = 9;
// 注意: 不看怎么存只看怎么取
printf("num8 = %u\n", num8);
printf("num9 = %u\n", num9);
printf("num10 = %u\n", num10);
return 0;
}
- 注意點:
- 修飾符號的說明符可以和修飾長度的說明符混合使用
- 相同類型的說明符不能混合使用
signed short int num1 = 666;
signed unsigned int num2 = 666; // 報錯