今天在做一個 16 進制 Mask 的時候出了一個 Warning.
private static int ShiftOverwrite(int original, uint mask, int value, int shift) { var maskedOriginal = (original & mask); var newBits = value << shift; return (int)(maskedOriginal | newBits); }
Warning 是這樣 warning CS0675: The operator `|’ used on the sign-extended type `int’. Consider casting to a smaller unsigned type first
原因是在 (original & mask) 的時候, 沒有做好 casting. original 是int , mask 是 uint.
原意是把原本的數值用 mask 把想關的位置取出
問題是怎樣 casting ? 以下是答案
private static int ShiftOverwrite(int original, uint mask, int value, int shift) { var maskedOriginal = (int)((uint)original & mask); var newBits = value << shift; return (int)(maskedOriginal | newBits); }
首先要把輸入的數字, 在這裡是用一個 int ARGB 的值來儲存 4 個 channel 的值.
ARGB = ShiftOverwrite(ARGB, 0xFF00FFFF, value, 16);
那麼
(original & mask) 則是 (ARGB & 0xFF00FFFF) 用作抽取 Red channel 的值.
所以先要把 original 由 (int) 轉為 (uint), mask 過之後再轉為 (int)
在這裡要惡補一下 uint 及 int 的分別
簡單的說 int 就是 interget 喇,
uint 就是 usign interger . 即是沒有負數的 int
但最重要的是他們的儲存空間大少, int 是 32 bit 的.
在 c# 裡有 int32 的 type. 意思就是一個 32 位長的二進制數.
裡面最左邊的 1bit 是用 (0,1) 作指定 正負數 (+/-) 所以餘下的長度就是 31
即是 2^31 次方 = 2147483648 就是佢的長度, 所以 0 ~ 2^31-1 就是它的可儲存範圍 0~2147483647 . 因為 0 本身佔一個位
正數的範圍就是 (0)2^31-1,
負數的範圍則是 (1)2^31 [0在正數的範圍所以負數會多一個位, Math bitch!]
如果 uint 的話因為多了一個 bit 做 2進制運算所以 2^32 的長度就可以盡用了
即是 0~2^32-1 即是 4294967296 是它的上限.
PS: 任可超過 2^31 的數值 cast 作 uint 是一定失敗的 :D, 因為沒地方存放.
簡單說 int -> uint 安全, 但 uint -> int 要留意有沒有 overflow.