參考資料:
C的char其實有三種,
signed char,-128 ~ 127
unsigned char,0 ~ 255
char,可能等於signed char或unsigned char,由OS環境或開發者決定
gcc寫的類似這樣:
/include/limits.h
#ifdef __CHAR_UNSIGNED__ /* -funsigned-char */
#define CHAR_MIN 0
#define CHAR_MAX UCHAR_MAX
#else
#define CHAR_MIN SCHAR_MIN
#define CHAR_MAX __SCHAR_MAX__
#endif
char的區間,在windows上目前看到都是-128 ~ 127,
Linux/Unix上-128 ~ 127或0 ~ 255都有看過,
不確定其他作業系統有無規定?
也不確定如何修改Linux/Unix上char的區間設定?
但是開發者在編譯程式時,可以透過指令設定char等於signed char或unsigned char:
g++ -std=c++11 -pthread -fsigned-char -Wall -ggdb -O2 -MMD -MP MyMainFile -o MyFolder/MyExe.out
g++ -std=c++11 -pthread -funsigned-char -Wall -ggdb -O2 -MMD -MP MyMainFile -o MyFolder/MyExe.out
編譯成unsigned char後,把執行檔複製到signed char的OS環境,執行檔還是會認為char等於unsigned char,
反之亦然
程式從外部或第三方元件讀入的資料為char型態時,要特別小心,譬如
把std::numeric_limits<unsigned char>::max()餵給signed char,會變成-1,
把std::numeric_limits<signed char>::min()餵給unsigned char,會變成128
這就是雞同鴨講,這種錯誤會造成蝴蝶效應,會接著引發許多災難
個人偏好設定char等於unsigned char,因為SQL的char也是0 ~ 255 (vchar range 0 ~ 65535),
0 ~ 255用16進位表示是0x00 ~ 0xFF,
證交所或其他金融領域常見的PackBCD格式,數值區間為0x00 ~ 0x99,用unsigned char儲存較方便
參考資料:
c++11開始多了靜態斷言(static_assert),能在開發時硬性規定程式該如何使用,否則編譯會跳錯
規定自己寫的程式char等於unsigned char:
static constexpr int CharMin = std::numeric_limits<char>::min();
static_assert(CharMin == 0, "Please use -funsigned-char.");
static constexpr int CharMax = std::numeric_limits<char>::max();
static_assert(CharMax == 255, "Please use -funsigned-char.");
OS環境如果是signed char,或是編譯時用了-fsigned-char,gcc會跳錯通知"Please use -funsigned-char.",
也會說明是哪個檔案的哪行程式碼跳錯
程式碼還能精簡(偷懶):
static constexpr int CharMin = std::numeric_limits<char>::min() == 0 ? 0 : throw std::invalid_argument("");
static constexpr int CharMax = std::numeric_limits<char>::max() == 255 ? 255 : throw std::invalid_argument("");
此時invalid_argument內就(偷懶)不加訊息了,因為不會顯示到gcc的編譯錯誤訊息上,但還是會顯示錯誤的檔案和行號
定義編譯規範可以增加程式碼的可讀性,讓其他開發者知道如何使用原開發者的程式碼
定義編譯規範可以加強程式碼的可移植性,能在不同平臺編譯出相同功能的程式,不同平臺間的訊息交換也能較一致
231111補充,並參考之前寫的 C語言的sizeof(long)和下一個千禧蟲問題
//強制只能編譯成64位元執行檔,否則編譯跳錯
static constexpr bool Is64Bit = sizeof(void *) == 8 ? true : throw std::invalid_argument("");
沒包袱的新專案建議只能在64位元環境執行就好
程式碼能自行設計編譯期檢查還有一個莫大的好處,
以前還要把滑鼠移到constexpr參數上,看數值是否正常,好累!
現在編譯時就會自動檢查,不正常會無法編譯