關於 C# warning CS0675: The operator `|’ used on the sign-extended

今天在做一個 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.

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

*

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料