---
# System prepended metadata

title: Camera OV7670 第02段 const和 uint8_t、uint16_t

---

# Camera OV7670 第02段 const和 uint8_t、uint16_t
```javascript=6
#define UART_MODE 5
const uint8_t VERSION = 0x10;
const uint8_t COMMAND_NEW_FRAME = 0x01 | VERSION;
const uint8_t COMMAND_DEBUG_DATA = 0x03 | VERSION;
const uint16_t UART_PIXEL_FORMAT_RGB565 = 0x01;
const uint16_t UART_PIXEL_FORMAT_GRAYSCALE = 0x02;
```
## 什麼是 const 

### 解釋1
 - 1:在定義變量時使用:
    總結:在使用const定義變量時，一定要進行初始化操作，在操作符(*,&)左邊的修飾的是指向的內容，在右邊的是本身。
    a: const int a=100;            最簡單的用法，設定說明變數a是一個常數變數。
    b: int const b=100;            與a功能相同。
    c: const int *a=&b;            指向常數的指針，即指針本身的值是可以改變的，但指向的內容是不能改變的。
    d: int const *a=&b;            與c功能相同。
    e: int * const a = &b;         常數指針，即指針本身的值是不可改變的，但指向的內容是可改變的。
    f: const int * const a = &b;   指向常數的常數指針，即指針本身與指向的內容都是不可改變的。
    g: const int &a=100;           常數引用，即不能改變引用的值。
 - 2:在函數用使用:
    總結:在函數中使用const，情況與定義變數的情況大致相同。
    a: void func(const int a);     做為參數使用，說明函數內是不能修改該參數的。
    b: const int func();           做為返回值使用，說明函數的返回值是不能被修改的。
    c: int func() const;           常數函數，說明函數是不能修改該類別中成員的值的，只能用於類別的成員函數中。
    - 應用原則
        1.先左由右，看左邊最近的是何種data type，若左邊沒有，則看右邊最近的。
        2.沿著*號劃一條線，
        如果const位於*的左側，則const就是用來修飾指標所指向的變數，即指標指向為常量。
        如果const位於*的右側，const就是修飾指標本身，即指標本身是常量。
        範本
        例一: const int * Constant1        --> const int (* Constant1)
        例二: int const * Constant2        --> int const (* Constant2)
        例三: int * const Constant3        --> (int *) const Constant3        --> const (int *) Constant3
        例四: int const * const Constant4  --> const (int *) const Constant4
        解答
        例一 int值不可被修改
        例二 int值不可被修改
        例三 指標值不可被修改
        例四 int值與指標值皆不可修改
 - 做個總結
    記憶體的位置可以變動,但是記憶體的內容不能變動
    const Parent* pParent1 = new SubA();

    記憶體的位置可以變動,但是記憶體的內容不能變動
    Parent const *pParent2 = new SubA();

    記憶體的內容可以變動,但是記憶體的位址不能變動
    Parent* const pParent3 = new SubA();

    記憶體的位址與內容都不能變動
    const Parent* const pParent4 = new SubA();

    記憶體的位置可以變動,但是記憶體的內容不能變動
    const Parent const *pParent5 = new SubA();
(參考網址{https://www.xuehua.tw/a/5ec8178c600636e92ea18dd5})

### 解釋2
很難對它下一個標準的定義，因為的用法很靈活，似乎對它定義後總無法讓人能夠明白它的意思
例如，它有定義：一個能夠讓變數變成無法修改的常量的關鍵字。
    那麼，這樣的話，就可能讓人誤解為只要有const在定義變數裡面，那變數就無論怎樣都無法修改。
    這樣的理解是很片面的（下面用法方面將對這問題做探討）。
1. 為了防止傳遞的函數參數不被修改，在調用函數的形參中用const關鍵字
```javascript=
int FindNum(const int array[], int num, int conut);//聲明函數
//code...
int FindNum(const int array[], int num, int count){
    int i;
    int flag = 1;
        for (i = 0; (i < count) && flag; i++){
        if (array[i] == num){
            flag = 0;
        break;
        }
        }
        return flag;
}
 //code...
```

上面這例子中，編譯器會把array[  ]當作常量資料的陣列看待。所以，假如你不小心給陣列賦值，那麼，編譯器就會報錯了。
因此，當你不需要也不想修改陣列的資料時，最好用const把陣列定義為常量陣列。
2. const可以用來創建陣列常量、指標常量、指向常量的指標等
```javascript=
    const char ch = 'a';
    const int a[5] = {1, 2, 3, 4, 5};  
    const int *p = a;                  //a是一個陣列的首位址.p是指向常量的指標
    int * const p = a;                 //a是一個陣列的首位址.p是指針常量；
    const int * const p = a;           //a是一個陣列的首位址。p是指向常量的指標常量
```

3. 前兩種情況很簡單，現在著重分析一下後三種用法，因為這情況容易出錯
  - 乾脆不用const.
   
```javascript=
   const int *p = a;
```

  - p是**指向常量**的指標，因此，不可以通過給**指標賦值**來改變陣列中的資料，例如：
```javascript=
    const int *p = a;
    *p = 10;       /*錯誤*/
    *(p + 2) = 1;  /*錯誤*/
```
假如指向常量指標可以改變值，那麼，就等於也改變了陣列的數。  
假如你不理解，就想你和一個人綁在一起，有可能你移動了位置而他不跟著你移動嗎！

 - 看這運算式，const的位置和第一個不同吧！他們的用法和作用就完全不一樣了。這時候p是指標常量
```javascript=
    int * const p = a;      
```

 - 我們知道，指標是指向了一個陣列的首位址，那麼，它的位置就不可以改變了。
 - 但是你現在應該和第一個運算式比較了，現在的陣列並不是常量陣列，所以陣列的資料是可以改變的
 - 而指標這時候它是不可以移動的，指向陣列第一個資料，所以它可以而且只可以改變陣列第一個 數據的值。
 - 這一點請別誤解，指標常量只是它的位址不可以改變，並不是它指向的內容一定不可以改變，這一點切記！

 - 好啦。假如你又不理解，又有一個比較形象的例子來說明：
   假如有一個固定的人拉著另外一個人的手，
   注意，固定的人相當於他是不可以由其他人來替換的。
   但是他可以拉其他人的手啊， 並不一定規定他必須拉同一個人的手啊。
   現在你應該可以有個比較深的印象和理解吧

下面舉幾個例子幫助理解：
```javascript=
    int * const p = a;
    *p = 2;          /*可以*/
    *(p+1) = 10;     /*可以*/
    p++;             /*不可以*/
```

- 假如前面兩種運算式的本質你理解了，這種運算式你來理解根本沒有問題，const現在有兩個，而且一個const的位置是第一種情況的位置，第二個const是第二種情況的位置，所以這運算式的功能就是前兩種情況的作用總合。
```javascript=
 const int * const p = a;
```

下面舉幾個例子幫助理解：
```javascript=
    const int * const p = a
    *p = 2;            /*不可以*/ 
    *(p + 2) = 10;     /*不可以*/
    p++;               /*不可以*/
```

 4. const並不會阻止參數的修改
 之所以把這作為一點來談，就是因為有一些朋友可能會以為在函數參數中用了const就一定不可以改變參數，這實際上是錯誤的理解，因為，它並不阻止參數的修改，下面舉個簡單的例子來闡述一下；
```javascript=
#include<stdio.h>
#include<ctype.h>
    
void ChangeStr(const char *String);
    int main(void){
    char str[] = "The C programme";
    Change(str);
    printf(str);
    system("Pause");
    return 0;
    }
void ChangeStr(const char *String){
    char *Source = (char *)String;
    while (*Source){
    *Source = toupper(*Source);
    Source++;
    }
    }
//end
```

上面的程式把字串中的每個字元都轉換成大寫字母了。因為String把地址給了Source，而Source的值的改變編譯器並不干涉，可能有的編譯器會發出警告之類。上面的程式只是為了說明const並不會阻止參數的修改，如果象上面程式那樣，個人感覺沒什麼意義，只會讓人容易混亂而已。

[參考網站](//https://www.xuehua.tw/a/5ec870da5da483795bb685f0)


## 什麼是uint8_t、uint16_t

1. 資料型態有分signed跟unsigned，用來表示正整數或者負數使用，C如果加上uint就代表是無號數(無符號數)的意思

2. 那後面的_t又是什麼意思呢?
代表的就是他是透過typedef而來，

3. typedef又是什麼?
就是有點像是幫資料型態另外定義命名，譬如你有一些使用上的習慣，你可以透過typedef來重新命名
而通常是透過這樣命名的

```javascript=
typedef unsigned char uint8_t; 
typedef unsigned short int uint16_t;
```

可以看到就是unsigned char 的型態，char又等於 1byte ,用bit來表示就是8bits

4. 無符號數是什麼?（unsigned）是計算機編程中的一種數值資料型別。
有符號數（signed）可以表示特定類型規定範圍內的整數（包括負數），而無符號數只能表示非負數（0及正數）。

有符號數能夠表示負數的代價是能夠表示的正數範圍的縮小，因為其約一半的數值範圍要用來表示負數
（如8位有符號整數中，對應8位無符號整數表示128~255的部分被用於表示-127~ -1）。無符號數可以利用其所占有的所有位來表示較大的數。

例如，16位有符號整數可表示 -32768~32767 之間的任意整數，而16位無符號整數可表示 0~65535 之間的數。若將有符號數轉換為二進位，則其數值類型允許的最左一位用於表示符號（1為負數，0為正數和0），但在無符號數中，最左一位與其右各位一樣用於表示數值。

參考網站(https://jefflin1982.medium.com/%E8%8F%9C%E9%B3%A5c-%E4%BB%80%E9%BA%BC%E6%98%AFunit8-t-99ce61277945)


