2016年12月12日 星期一

C#使用指標雜談

C#使用指標並不是什麼很厲害的技術,新手除外,稍微對C#有更深入一些經驗的人,我猜多數都有在C#使用指標的經驗,所以我這邊主要也不是要介紹C#使用指標這件事情,而是雜談些別的.

C#雖然可以使用指標,但如果是一般的方式
https://msdn.microsoft.com/zh-tw/library/f58wzh21.aspx
也就是搭配 fixed 陳述式 , 跟 C 指標操作存取相比會顯得非常沒彈性 , 所以在C#達不到C操作指標的靈活度.......但如果使用 Marshal 來進行 unmanaged 的記憶體配置拿到指標 , 則在C#中則"幾乎"(還有不少確認和爭議空間)可以達到 C 操作指標的靈活度

Marshal.AllocHGlobal
Marshal.FreeHGlobal

這兩的東西好用至極,之後要存取物件的習慣也幾乎跟C一樣,詳細的使用介紹就自行google,不多談.

這邊要說到的是有了這項能力後,處理模擬器其中一個問題顯然簡單而且有效率很多,電腦世界中雖然最基本的資料單位是 bits , 但硬體上資料能存取的最基本單元是 bytes , 8bit CPU 要模擬記憶體的硬體機本上宣告一個固定大小以byte為資料型態的array即可 , 不過到了32bit CPU一次存取可能就是 half-word (2bytes) 或是 word (4byte) , 有時候你從一個位址讀資料可能是要讀一個 byte , 有時候可能是一個 ushort , 有時候可能是一個 uint .



如果要讀4個byte, 你可以自己對 byte array 讀取4次  , 然後用 bitwise 的操作自己串成一個 uint ,顯然是麻煩 , 使用指標的狀況下 ,你可直接指定說我要從這指標的某個offset讀取 byte ushort uint 位元長度資料.

            byte* bytepointer = (byte*)Marshal.AllocHGlobal(sizeof(byte) * 16);

            bytepointer[0] = 0x00;
            bytepointer[1] = 0x11;
            bytepointer[2] = 0x22;
            bytepointer[3] = 0x33;
            bytepointer[4] = 0x44;
            bytepointer[5] = 0x55;
            bytepointer[6] = 0x66;
            bytepointer[7] = 0x77;
            bytepointer[8] = 0x88;
            bytepointer[9] = 0x99;
            bytepointer[10] = 0xaa;
            bytepointer[11] = 0xbb;
            bytepointer[12] = 0xcc;
            bytepointer[13] = 0xdd;
            bytepointer[14] = 0xee;
            bytepointer[15] = 0xff;

            ushort t_us;
            t_us =   ((ushort*) &bytepointer[4])[0];
            Console.WriteLine(t_us.ToString("x4"));
            t_us = ((ushort*)&bytepointer[9])[0];
            Console.WriteLine(t_us.ToString("x4"));

            uint t_ui;
            t_ui = ((uint*)&bytepointer[2])[2];
            Console.WriteLine(t_ui.ToString("x8"));
            t_ui = ((uint*)&bytepointer[4])[1];
            Console.WriteLine(t_ui.ToString("x8"));
            t_ui = ((uint*)&bytepointer[9])[0];
            Console.WriteLine(t_ui.ToString("x8"));
            Marshal.FreeHGlobal((IntPtr)bytepointer);

資料存取變得像切豆腐一樣容易,對於資料長度讀取的轉換可以任意有彈性來做.

不管是Read 8/16/32 或是 Write 8/16/32 ,把資料長度型態改變, 對可以對應了.

2016年12月6日 星期二

移植雜談

測試了一下網路上別人寫出的ntsc掃描線模擬函庫,出來的效果完全是我的想要的效果,太完美了,嘗試實作自己的一套,但要去理解ntsc畫面訊號規格太複雜,至少對我來說需要不少時間,於是打算使用移植的方式,從C移植到C#去,最後C#整個都在跟指標打交道,出現照理來說C#不常看到的 -> & 等等符號...但其實從C/C++移植最難的反來不是指標(甚至照理來說應該要把指標的處理方式給改寫掉比較符合風格上的正確),而是寫C的人很習慣把玩巨集和一些前置條件,而寫C++寫到狂的人則超愛用一堆複雜的樣板到讓人有走火入魔的感覺,還有一堆詭異C++近年來的新語法規格,這些移植到C#都相當麻煩.