在將 C++ 影像處理演算法移植至 C# 時,發現使用 uint* 指標存取 32 位 ARGB 位圖的邏輯並不完全相容。C++ 中 UINT* 每次遞增 (++) 正好移動一個像素 (4 字節);但 C# 若直接套用此邏輯,當 Stride != Width * 4 (即鎖定部分區域或記憶體對齊導致每行有填充位元組) 時,會發生存取越界或資料錯誤。
UINT* 指標運算以型別大小 (4 bytes) 為單位,ptr++ 等同 ptr + 1,自動跨越一個像素。uint* 行為相同,但 位圖資料在記憶體中是連續的位元組流,行寬由 BitmapData.Stride 決定。若 Stride > Width * 4,每行末尾有填充位元組,單純用 ++ 會誤讀填充區,導致下一行起始位置偏移。無論語言,安全做法皆為 位元組指標 (byte*) + 手動計算位移:
// 假設 bitmapData 為 Bitmap.LockBits 取得的 BitmapData
byte* ptr = (byte*)bitmapData.Scan0.ToPointer();
int stride = bitmapData.Stride; // 可能為負值 (自下而上)
for (int y = 0; y < height; y++)
{
byte* row = ptr + y * stride;
for (int x = 0; x < width; x++)
{
// 取得第 x 個像素的 ARGB (32 bits = 4 bytes)
uint pixel = *(uint*)(row + x * 4);
// ... 處理 pixel ...
// 寫回
*(uint*)(row + x * 4) = newPixel;
}
}
LockBits 整張圖時,通常 Stride == Width * 4,此時 uint* 遞增 可能 僅能運氣好不出錯,但不可靠。LockBits 指定矩形區域時,Stride 幾乎必定大於 Width * 4,直接用 uint* 遞增 必定出錯。byte* 迴圈優化極好,且避免難以除錯的記憶體錯誤,強烈建議統一使用 byte* 配合 Stride 計算。C# 位圖指標操作務必尊重 Stride,採用 byte* 逐位元組定址,才能在所有鎖定模式下正確、穩定地處理像素資料。