青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

longshanks

  C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
  14 Posts :: 0 Stories :: 214 Comments :: 0 Trackbacks

常用鏈接

留言簿(10)

我參與的團隊

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

三只小豬
莫華楓

    小時候聽說過三只小豬的故事,隱約記得故事是講三只小豬用不同方法造房子,對抗老狼。這些天做軟件,遇到一個無比簡單的問題,但在三種不同的語言中,卻有著截然不同的解法。

    最近,冷不丁地接到公司下派的一個緊急任務,做手持POS和PC程序之間交換數據的程序。各種各樣的麻煩中,有一個小得不起眼的問題,POS機中數據的字 節序和PC相反。這可不算是什么啊。沒錯,是在太簡單了。盡管如此,還是引發了一場爭論。做POS程序的,希望PC程序做轉換。做PC程序的,希望POS 程序做轉換。(誰都想少做點,對吧;))。最終,作為和事佬的我,為了維護和諧的氛圍,攬下了這件事。當然,到底在那里做,還是要決定的。最終選擇在PC 上,畢竟PC上調試起來容易。(天煞的,這個POS機沒有debug,也沒有模擬器,顯示屏還沒我手機的大,做起來著實費事)。
    其實,我的本意是想在POS上做這個轉換。因為POS用的是C(一個不知什么年代的gcc),可以直接操作字節。基本的代碼看起來差不多應該是這樣:
        unsigned long InvData(unsigned long val, int n) {
            unsigned long t=val, res=0;
            for(; n >0; n--)
            {
                res = res << 8;
                res |= (unsigned char)t;
                t = t >> 8;
            }
            return res;
        }
    n是數據類型的字節長度。這里使用了最長的無符號整數類型。這是核心轉換函數,各種類型的轉換函數都可以從中派生:
        long InvDataLong(long val) {
            return (long)InvData((unsigned long)val, sizeof(val));
        }
        short InvDataShort(short val) {
            return (short)InvData((unsigned short)val, sizeof(val));
        }
        ...
    最后,有一個比較特殊的地方,float。float的編碼不同于整型,如果直接用(unsigned long)強制類型轉換,只會把float數值的整數部分賦予參數,得不到正確的結果。正確的做法,應當是把float占用的四個字節直接映射成一個 unsigned long:
        float InvDataFloat(float val) {
            float val=InvData(*(unsigned long*)(&val), sizeof(val));
            return *(float*)(&val);
        }
    通過將float變量的地址強制轉換成unsigned long*類型,然后再dereference成unsigned long類型。當然還有其他辦法,比如memcpy,這里就不多說了。至于double類型,為了簡化問題,這里將其忽略。如果有64位的整型,那么 double可以采用類似的解法。否則,就必須寫專門的處理函數。
    當然,最終我還是使用C#寫這個轉換。相比之下,C#的轉換代碼顯得更具現代風味。基本算法還是一樣:
        public static ulong DataInv(ulong val, int n)
        {
            ulong v1_ = val, v2_ = 0;

            for (; n > 0; n--)
            {
                v2_ <<= 8;
                v2_ |= (byte)v1_;
                v1_ >>= 8;
            }

            return v2_;
        }
    對于習慣于C/C++的同學們注意了,long/ulong在C#中不是4字節,而是8字節。也就是C/C++中的longlong。以這個函數為基礎,其它整數類型的字節序轉換也就有了:
        public static ulong DataInv(ulong val)
        {
            return DataInv(val, sizeof(ulong));
        }

        public static uint DataInv(uint val)
        {
            return (uint)DataInv((ulong)val, sizeof(uint));
        }

        public static int DataInv(int val)
        {
            return (int)DataInv((uint)val);
        }
        ...
    然而,面對float,出現了麻煩。在C#中,沒有指針,無法象C那樣將float展開成ulong。(unsafe代碼可以執行這類操作,但這不是C#嫡親的特性,并且是違背C#設計理念的。這里不做考慮)。C#提供了另一種風格的操作:
        public static float DataInv(float val)
        {
            float res_ = 0;

            byte[] buf_ = BitConverter.GetBytes(val);
            byte t = 0;

            t = buf_[0];
            buf_[0] = buf_[3];
            buf_[3] = t;

            t = buf_[1];
            buf_[1] = buf_[2];
            buf_[2] = t;

            res_ = BitConverter.ToSingle(buf_, 0);

            return res_;
        }
    這個做法盡管有些累贅,但道理上很簡單:把float變量轉換成一個字節流,然后把相應的位置對調,就獲得了字節反序的float。相比C的float轉 換,C#明顯不夠簡練。原因很簡單,C#根本不是用來干這個的。C是一種非常底層的語言,它的內存模型是完全直觀的,與硬件系統相對應的。因而,對于這種 與機器相關的操作,當然也顯得游刃有余。而C#定位于高層開發的高級語言,底層的內存模型是被屏蔽的,程序員無需知道和關心。
    不過,C#的代碼卻擁有它的優勢。只需看一眼這些函數的使用代碼,便不言自明了:
        //C代碼
        int x=234;
        float y=789.89;
        short z=332;
        x=InvDataInt(x);
        y=InvDataFloat(y);
        z=InvDataShort(z);

        //C#代碼
        int x=234;
        float y=789.89;
        short z=332;
        x=DataInv(x);
        y=DataInv(y);
        z=DataInv(z);
    在C代碼中,對于不同的類型,需要使用不同命名的函數。而在C#代碼中,則只需使用DataInv這樣一個函數名。至于屆時選用那個版本的函數,編譯器會 根據實際的類型自動匹配。C#運用函數重載這個特性,使得調用代碼可以采用統一的形式。即便是數據的類型有所變化,也無需對調用代碼做任何修改。(這在我 的開發過程中的得到了驗證,傳輸數據的成員類型曾經發生變化,我也只是修改了數據結構的定義,便將問題搞定)。這一點,在C中是無法做到的。
    歸結起來,C由于側重于底層,在數據轉換方便的靈活性,使得轉換代碼的構建更加容易。而C#則得益于函數重載,在轉換代碼使用方面,有獨到的優勢。
    迄今為止,三只小豬中,還只有兩只出現。下面就要第三只出場了。
    作為C++的粉絲,我會自然而然地想到使用C++來實現這個轉換功能。于是便有了如下的代碼:
       unsigned long InvData(unsigned long val, int n) {
            unsigned long t=val, res=0;
            for(; n >0; n--)
            {
                res = res << 8;
                res |= (unsigned char)t;
                t = t >> 8;
            }
        }
        long InvData(long val) {
            return (long)InvData((unsigned long)val, sizeof(val));
        }
        short InvData(short val) {
            return (short)InvData((unsigned short)val, sizeof(val));
        }
        ...
        float InvData(float val) {
            float val=InvData(*(unsigned long*)(&val), sizeof(val));
            return *(float*)(&val);
        }
    這些代碼就好象是C和C#代碼的雜交后代。既有C的底層操作,也有C#的函數重載,兼有兩者的優點。
    不過,還能做得更好:
        template<typename T>
        T InvData(T val) {
            T t=val, res=0;
            int n=sizeof(T);
            for(; n >0; n--)
            {
                res = res << 8;
                res |= (unsigned char)t;
                t = t >> 8;
            }
            return (T)res;
        }
    這樣,就把所有的整型都一網打盡了,僅用一個函數模板,便完成了原先諸多函數所做的工作。而float版本的函數則保持不變,作為InvData()的一個重載。按照C++的函數模板-重載規則,float版的函數重載將被優先使用。

    好了,三只小豬的故事講完了。前兩只小豬各有優點,也各有缺點。而第三只小豬則雜合和前兩者的優點,并且具有更大的進步。盡管第三只小豬存在各種各樣的缺陷,但畢竟它的眾多特性為我們帶來了很多效率和方便,這些還是應當值得肯定的。

附:第三只小豬的其他手段:
1、強制轉換成字符串數組
template<typename T>
T InvData1(T v) {
    unsigned char* pVal1=(unsigned char*)(&v)
        , *pVal2=pVal1+sizeof(T)-1, t;
    while(pVal2-pVal1>1)
    {
        t=*pVal2;
        *pVal2=*pVal1;
        *pVal1=t;
        pVal1++;
        pVal2--;
    }
    return v;
}
2、使用標準庫,blog上有人留言建議的
template<typename T>
T InvData(T v) {
    unsigned char* pVal=(unsigned char*)(&v);
    size_t n=sizeof(T);
    std::reverse(pVal, pVal+n, pVal);
}
3、使用traits
template<size_t n> struct SameSizeInt;
template<> struct SameSizeInt<1> { typedef unsigned char Type; };
template<> struct SameSizeInt<2> { typedef unsigned short Type; };
template<> struct SameSizeInt<4> { typedef unsigned long Type; };
template<> struct SameSizeInt<8> { typedef unsigned longlong Type; };

template<typename T>
T InvData(T v) {
    size_t n=sizeof(T);
    typedef SameSizeInt<sizeof(T)>::Type NewT;
    NewT v1=*(NewT*)(&v), v2=0;
    for(; n >0; n--)
    {
        v2= v2<< 8;
        v2|= (unsigned char)v1;
        v1 = v1 >> 8;
    }
    return *(T*)(&v2);
}

甚至可以使用tmp去掉其中的循環。在C++中,這類任務的實現方法,完全看程序員的想象力了。:)
posted on 2008-09-18 19:25 longshanks 閱讀(1966) 評論(3)  編輯 收藏 引用

Feedback

# re: 三只小豬[未登錄] 2008-09-19 08:06 FongLuo
還有第四只小豬(適合C/C++):
將需要轉換的數據強制轉換為BYTE數組,再進行數組的頭尾交換(反轉,STL中有現成的算法),只要數組長度/2次交換就可以完成了。  回復  更多評論
  

# re: 三只小豬 2008-09-19 09:19 Louix
unsigned int target;
unsigned int result = ( target << 16 ) | ( target >> 16 );
result = ( ( result & 0xFF00FF00 ) >> 8 ) | ( ( result & 0x00FF00FF ) << 8 );

好處就是沒有循環的跳轉,會更快一些。  回復  更多評論
  

# re: 三只小豬 2010-01-14 19:17 EvieOn
One, who knows something about <a href="http://www.essaysprofessors.com/custom-writing.html">custom writing</a> should value your supreme release. I do think that the <a href="http://www.essaysprofessors.com/buy-a-paper.html">buy a paper</a> service could utilize it for the essay assignment blogs.   回復  更多評論
  


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            午夜亚洲一区| 亚洲高清在线播放| 欧美在线视频一区二区| 亚洲午夜伦理| 亚洲一区在线免费| 亚洲免费在线电影| 一区二区三区精品| 免费亚洲电影在线| 亚洲精品视频在线播放| 99国产一区二区三精品乱码| 亚洲欧洲在线观看| 一区二区三区四区五区在线| 亚洲视频播放| 欧美资源在线| 欧美激情免费在线| 国产精品v日韩精品v欧美精品网站| 欧美日韩国产精品成人| 欧美日韩一二三区| 国产亚洲美州欧州综合国| 精品51国产黑色丝袜高跟鞋| 99riav久久精品riav| 久久av一区二区三区亚洲| 久久九九99| 亚洲精品乱码久久久久久久久| 亚洲午夜电影网| 美国成人毛片| 国产九九视频一区二区三区| 亚洲精品视频一区| 欧美一级日韩一级| 亚洲国产精品日韩| 性一交一乱一区二区洋洋av| 老司机成人网| 国产精品影院在线观看| 亚洲美女精品久久| 久久天天躁狠狠躁夜夜av| 99热这里只有精品8| 可以看av的网站久久看| 国产伦精品一区二区三区| 亚洲精品久久久一区二区三区| 亚洲欧美日韩在线综合| 欧美成人精品1314www| 亚洲视频久久| 欧美精品18+| 亚洲国产精品精华液2区45| 久久精品国产第一区二区三区| 亚洲精品一区在线观看| 麻豆精品在线视频| 精品51国产黑色丝袜高跟鞋| 欧美一级视频免费在线观看| 亚洲日韩第九十九页| 麻豆精品一区二区综合av| 一区二区三区在线免费观看| 久久国内精品视频| 亚洲女女女同性video| 欧美性猛交视频| 亚洲一区自拍| 亚洲亚洲精品在线观看| 国产精品播放| 一区二区高清视频| 91久久在线播放| 欧美极品在线视频| 亚洲国产合集| 亚洲第一区在线观看| 免费一级欧美片在线播放| 亚洲精品中文字幕有码专区| 99视频精品在线| 欧美高清不卡| 亚洲国产精品一区二区第四页av | 农夫在线精品视频免费观看| 在线观看三级视频欧美| 久久久久久久久久久一区 | 一区二区久久久久久| 国产一区二区三区无遮挡| 亚洲第一在线综合网站| 欧美阿v一级看视频| 亚洲一区免费网站| 国产精品一区二区在线观看| 西瓜成人精品人成网站| 羞羞视频在线观看欧美| 国内成+人亚洲+欧美+综合在线| 久久色中文字幕| 久久综合狠狠综合久久激情| 亚洲激情在线观看视频免费| 亚洲日韩欧美一区二区在线| 欧美体内she精视频在线观看| 午夜精品www| 久久久久久穴| 一区二区三区.www| 91久久在线视频| 国产精品久久久久三级| 久久精品一区二区三区不卡牛牛| 亚洲欧美成人网| 亚洲黄色毛片| 亚洲色在线视频| 国产在线成人| 欧美18av| 国产精品国产三级国产专区53| 欧美一级一区| 欧美韩国日本一区| 久久精品免视看| 欧美连裤袜在线视频| 久久精品成人一区二区三区蜜臀 | 亚洲人成在线观看网站高清| 9久re热视频在线精品| 国产日产欧美a一级在线| 欧美福利影院| 国产精品亚洲综合天堂夜夜| 美女亚洲精品| 欧美日韩日日夜夜| 美女日韩在线中文字幕| 国产精品久久午夜| 亚洲第一黄色网| 国产伦精品一区二区三区免费迷| 欧美高清在线一区| 欧美成人精品不卡视频在线观看| 亚洲一区二区三区影院| 亚洲欧美不卡| 一本久道久久久| 久久精品一区二区国产| 亚洲一区二区三区视频| 女女同性女同一区二区三区91| 久久激情五月丁香伊人| 欧美视频亚洲视频| 亚洲国产精品999| 国内综合精品午夜久久资源| 在线亚洲一区二区| 亚洲乱亚洲高清| 蜜臀av性久久久久蜜臀aⅴ四虎| 欧美一区二区三区久久精品茉莉花| 你懂的网址国产 欧美| 欧美大学生性色视频| 激情综合色综合久久| 欧美在线视频观看免费网站| 亚洲欧美日韩精品久久奇米色影视| 欧美成人自拍视频| 欧美激情在线狂野欧美精品| 国内成人自拍视频| 久久se精品一区精品二区| 欧美专区在线| 国内视频一区| 亚洲欧美视频一区| 香蕉亚洲视频| 国产精品综合| 久久精品99国产精品| 老色批av在线精品| 激情综合自拍| 久久精品中文字幕免费mv| 久久另类ts人妖一区二区| 国产亚洲欧洲一区高清在线观看| 欧美一级视频免费在线观看| 午夜一级久久| 国产免费成人在线视频| 欧美一区二区三区在线观看视频| 久久激情一区| 在线观看欧美日韩国产| 久久亚洲不卡| 欧美成在线观看| 亚洲国产精品久久久久秋霞不卡 | 亚洲一区二区成人在线观看| 亚洲欧美国产制服动漫| 国产女人18毛片水18精品| 欧美诱惑福利视频| 久久综合国产精品台湾中文娱乐网| 永久免费精品影视网站| 欧美日本不卡视频| 亚洲综合精品一区二区| 老牛嫩草一区二区三区日本| 日韩一级裸体免费视频| 国产欧美亚洲日本| 久久男人资源视频| 最新国产成人av网站网址麻豆| 99re国产精品| 国产乱码精品一区二区三区忘忧草 | 日韩一区二区久久| 久久久国产精品一区二区三区| 亚洲国产福利在线| 国产一区久久久| 欧美电影电视剧在线观看| av成人手机在线| 国产日韩在线一区| 卡一卡二国产精品| 亚洲一区免费视频| 91久久精品国产91性色tv| 久久精品国产视频| 亚洲精品在线电影| 国内成+人亚洲+欧美+综合在线| 欧美高清视频在线观看| 西西裸体人体做爰大胆久久久| 亚洲国产经典视频| 久久久夜精品| 性色av香蕉一区二区| 99热在这里有精品免费| 国产日韩欧美在线观看| 欧美屁股在线| 欧美成人激情视频| 久久噜噜噜精品国产亚洲综合| 一本色道**综合亚洲精品蜜桃冫 | 亚洲一区日韩在线| 亚洲人www| 欧美激情四色|