前往
大廳
主題

雞同鴨講1,char的邊界值和編譯期檢查

Yang | 2023-11-04 16:28:01 | 巴幣 0 | 人氣 121

參考資料:

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參數上,看數值是否正常,好累!

現在編譯時就會自動檢查,不正常會無法編譯
送禮物贊助創作者 !
0
留言

創作回應

更多創作