• <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>

            C/C++圖形圖像的世界

            圖形與游戲編程

            常用鏈接

            統(tǒng)計(jì)

            積分與排名

            Blog

            最新評(píng)論

            2012年1月16日 #

            C/C++宏的奇技淫巧

            來(lái)源:http://blog.misakamm.org/p/209
            宏的主要作用就是簡(jiǎn)化代碼編寫(xiě),簡(jiǎn)化一些需要重復(fù)編碼的地方,以得到看起來(lái)更優(yōu)雅的代碼。但宏要用得好并不容易,用的不好很容易引發(fā)災(zāi)難性的后果。本文會(huì)介紹宏比較偏門(mén)但又很實(shí)用的技巧。
            首先就是最常用的技巧(http://blog.misakamm.org/p/209):
            #define MACROCAT( x, y ) MACROCAT1 ( x, y )
            #define MACROCAT1( x, y ) x##y
            #define TOSTRING( s ) #s
            MACROCAT把x和y展開(kāi)后連結(jié),而TOSTRING把s轉(zhuǎn)化為字符串,比如可以printf(TOSTRING(%s), TOSTRING(abcdefg));
            然后,因?yàn)楹瓴荒苓f歸,但可以做遞歸模擬,我們可以這樣玩。比如要生成n位的二進(jìn)制數(shù)并且從小到大構(gòu)成的字符串(用到前面的宏):
            #define BIN_0(arg) TOSTRING ( arg )
            #define BIN_1(arg) BIN_0(MACROCAT(arg, 0)) "," BIN_0(MACROCAT(arg, 1))
            #define BIN_2(arg) BIN_1(MACROCAT(arg, 0)) "," BIN_1(MACROCAT(arg, 1))
            #define BIN_3(arg) BIN_2(MACROCAT(arg, 0)) "," BIN_2(MACROCAT(arg, 1))
            #define BIN_4(arg) BIN_3(MACROCAT(arg, 0)) "," BIN_3(MACROCAT(arg, 1))
            int main()
            {
            puts(BIN_4());
            return 0;
            }

            這里要注意的是,比如BIN_2(),實(shí)際上展開(kāi)的結(jié)果是
            "0" "0" "," "0" "1" "," "1" "0" "," "1" "1"
            不過(guò)c/c++規(guī)定這樣連寫(xiě)的字符串,編譯時(shí)就會(huì)合并成一個(gè),于是就能用puts直接完整輸出結(jié)果了
            如果你想得到更多的位,很簡(jiǎn)單,只要你不介意,上面的宏復(fù)制并改改數(shù)字就可以了
            不過(guò),這樣一改要改若干個(gè)數(shù)字,比較麻煩,能不能讓它工作得更好?比如只要改宏名?
            這個(gè)時(shí)候,就要用更富有技巧性的一招了:讓每個(gè)宏多一個(gè)參數(shù)n,然后前面的BIN_x使用MACROCAT把它與數(shù)字連結(jié)起來(lái),不就可以了么?
            想法不錯(cuò),不過(guò)問(wèn)題是宏本身沒(méi)有做減法的能力,能做的僅僅是替換。減1應(yīng)該怎么實(shí)現(xiàn)呢?
            其實(shí)不難,見(jiàn)以下定義:
            #define DECVAL_1 0
            #define DECVAL_2 1
            #define DECVAL_3 2
            #define DECVAL_4 3
            #define DECVAL_5 4
            #define DECVAL_6 5
            #define DECVAL_7 6
            #define DECVAL_8 7
            #define DECVAL_9 8
            #define DECVAL( n ) DECVAL_##n
            好了,有了這個(gè)利器,我們就可以對(duì)原宏改造了,先拿0號(hào)和1號(hào)宏開(kāi)刀:
            #define BIN_0(n, arg) TOSTRING ( arg )
            #define BIN_1(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 0)) \
            "," MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
            看得懂替換了一些什么嗎?這樣,后面的2,3,4,5號(hào),只要復(fù)制一下1號(hào)的定義,改一改宏名就解決問(wèn)題了
            思考題:
            這里生成的二進(jìn)制結(jié)果是帶前導(dǎo)0的,如何改寫(xiě)能使生成的結(jié)果不帶前導(dǎo)0?
            source: http://blog.misakamm.org/p/209

            使用此法可以“遞歸”式生成很多類似代碼,同時(shí)這個(gè)技巧也非常的實(shí)用,但遞歸構(gòu)造并不容易,需要編寫(xiě)的人仔細(xì)想清楚,否則很容易出錯(cuò),特別要注意宏展開(kāi)的時(shí)機(jī),一般不直接使用MACROCAT1宏,因?yàn)槟莻€(gè)很可能不是你想要的結(jié)果
            之后,到C99標(biāo)準(zhǔn)出臺(tái)后(也就是說(shuō),下文內(nèi)容與bc3/tc/vc6不兼容),宏里面多了一個(gè)狠角色:可變參數(shù)個(gè)數(shù)宏
            比如可以 #define PRINTF(...) fprintf(stdout, __VA_ARGS__)
            其中__VA_ARGS__代表了‘...’部分的全部參數(shù),這樣可以輕松的重定義庫(kù)函數(shù)里不定參數(shù)的函數(shù)的輸出行為,比如printf重定向到文件(雖然也可以用freopen實(shí)現(xiàn),但只想說(shuō)明宏也可以這樣搞)
            好了,下文將區(qū)分編譯器來(lái)介紹,一共分為兩派,vc派和gcc派(包括clang/objc),因?yàn)閮烧邔?duì)以下代碼的處理并不一致,需要使用略為不同的宏來(lái)實(shí)現(xiàn),目前我也只遇到這兩派。
            現(xiàn)在的目的是這樣,因?yàn)開(kāi)_VA_ARGS__包含了若干參數(shù),我怎么才能知道里面參數(shù)有多少個(gè)呢?
            比如寫(xiě)一個(gè)宏NUM_PARAMS(),里面寫(xiě)NUM_PARAMS(abc,a,d,e)的話,替換后得到的結(jié)果要是4,能辦到嗎?
             
             
             
             
             
             
             
             
             
             
            廣告時(shí)間:
            http://blog.misakamm.org/p/209
            廣告過(guò)后,回來(lái)精彩的節(jié)目
             
             
             
             
             
             
             
             
             
             
            首先先介紹gcc派的解決方案:
            #define PP_NARG(...) PP_NARG_(__VA_ARGS__, PP_RSEQ_N())
            #define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
            #define PP_ARG_N( \
            _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
            _11,_12,_13,_14,_15,_16, N, ...) N
            #define PP_RSEQ_N() \
            16,15,14,13,12,11,10, \
            9,8,7,6,5,4,3,2,1,0
            非常漂亮巧妙又簡(jiǎn)潔的方案,我想不用我多解釋了吧?
            不過(guò),請(qǐng)注意,這是gcc的方案,以上代碼放在vc8/vc9/vc2010等都會(huì)得不到正確的結(jié)果的,這個(gè)和vc的宏處理方式有關(guān)
            接下來(lái)就是給出vc的解決方案(以下均以vc2008和vc2010為準(zhǔn))
            #define BRACKET_L() (
            #define BRACKET_R() )
            #define PP_NARG(...) \
            PP_NARG_ ( __VA_ARGS__, PP_RSEQ_N() )
            #define PP_NARG_(...) \
            PP_ARG_N BRACKET_L() __VA_ARGS__ BRACKET_R()
            #define PP_ARG_N( \
            _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
            _11,_12,_13,_14,_15,_16, N,...) N
            #define PP_RSEQ_N() \
            16,15,14,13,12,11,10, \
            9,8,7,6,5,4,3,2,1,0
            
            這里很特別的一點(diǎn)是對(duì)部分小括號(hào)做了替換。
            問(wèn)題在于PP_NARG_到PP_ARG_N做參數(shù)傳遞的時(shí)候,如果已有顯式的括號(hào),那么不對(duì)里面的宏做展開(kāi)計(jì)算參數(shù)個(gè)數(shù),僅直接按顯式的逗號(hào)個(gè)數(shù)判斷出參數(shù)個(gè)數(shù),從而導(dǎo)致__VA_ARGS__被當(dāng)成一個(gè)參數(shù)傳入。而把括號(hào)用宏替換掉后,則不出現(xiàn)直接的括號(hào),就先對(duì)宏做展開(kāi),而展開(kāi)后,再展開(kāi)新構(gòu)造出來(lái)的宏,這樣才能讓參數(shù)匹配上。
            不過(guò)gcc里面不能這么干,gcc會(huì)把宏名展開(kāi)出來(lái)后,如果發(fā)現(xiàn)后面的符號(hào)并不是顯式的括號(hào),則把前面的宏符號(hào)化,不再展開(kāi)。這兩種不同的特性讓我現(xiàn)在還不知道怎么編寫(xiě)宏能讓兩派都能兼容,正確展開(kāi)出我想要的東西。
            解釋了兩個(gè)編譯器的不同點(diǎn)以后,后面不再解釋相同的問(wèn)題,而會(huì)同時(shí)給出兩份代碼。
            另一個(gè)類似的問(wèn)題,就是既然有不定個(gè)數(shù)的參數(shù),如果我希望對(duì)每個(gè)參數(shù)都做一些處理,那如何做呢?
            舉例,實(shí)現(xiàn)一個(gè)宏#define SPREAD(...),要把參數(shù)里的東西連結(jié)成一個(gè)字符串
            之前的例子里,已經(jīng)實(shí)現(xiàn)了把不定參數(shù)展開(kāi)的手段,現(xiàn)在我們來(lái)嘗試遞歸下降式展開(kāi)(gcc版本):
            #define SPREAD0( arg ) #arg
            #define SPREAD1(arg, ...) SPREAD0(arg)
            #define SPREAD2(arg, ...) SPREAD0(arg) SPREAD1(__VA_ARGS__,)
            #define SPREAD3(arg, ...) SPREAD0(arg) SPREAD2(__VA_ARGS__,)
            #define SPREAD4(arg, ...) SPREAD0(arg) SPREAD3(__VA_ARGS__,)
            #define SPREAD5(arg, ...) SPREAD0(arg) SPREAD4(__VA_ARGS__,)
            #define SPREAD6(arg, ...) SPREAD0(arg) SPREAD5(__VA_ARGS__,)
            #define SPREAD7(arg, ...) SPREAD0(arg) SPREAD6(__VA_ARGS__,)
            #define SPREAD8(arg, ...) SPREAD0(arg) SPREAD7(__VA_ARGS__,)
            #define SPREAD9(arg, ...) SPREAD0(arg) SPREAD8(__VA_ARGS__,)
            #define SPREAD(...) SPREAD9(__VA_ARGS__)
            在這里,每進(jìn)入一層,就從__VA_ARGS__拆解一個(gè)最前面的參數(shù)出來(lái),把剩下的參數(shù)給下一層
            這里有一個(gè)細(xì)節(jié)是__VA_ARGS__后面有一個(gè)逗號(hào),意思就是補(bǔ)一個(gè)空參數(shù),避免后面參數(shù)不足
            然后就可以用puts(SPREAD(1, 2, 3, 4));來(lái)測(cè)試了
            當(dāng)然,還要使用前文的方式處理一下(gcc版):
            #define SPREAD0( arg ) #arg
            #define SPREAD1(n, arg, ...) SPREAD0(arg)
            #define SPREAD2(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
            #define SPREAD3(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
            #define SPREAD4(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
            #define SPREAD5(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
            #define SPREAD6(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
            #define SPREAD7(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
            #define SPREAD8(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
            #define SPREAD9(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
            #define SPREAD(...) SPREAD9 ( 9, __VA_ARGS__ )
            vc版:
            #pragma warning(disable:4003) // 去除警告
            #define SPREAD0( arg ) #arg
            #define SPREAD1(n, arg, ...) SPREAD0(arg)
            #define SPREAD2(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
            #define SPREAD3(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
            #define SPREAD4(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
            #define SPREAD5(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
            #define SPREAD6(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
            #define SPREAD7(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
            #define SPREAD8(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
            #define SPREAD9(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
            #define SPREAD(...) SPREAD9 BRACKET_L() 9, __VA_ARGS__, BRACKET_R()
            以上只是模糊方式展開(kāi),因?yàn)閰?shù)個(gè)數(shù)不知道,后面會(huì)遇到宏參數(shù)為空的情況,于是vc編譯器給出了警告
            如果把之前說(shuō)的過(guò)技巧,就是分析出不定參數(shù)個(gè)數(shù)的宏,與這個(gè)結(jié)合,將產(chǎn)生更大的威力,我們可以實(shí)現(xiàn)精確展開(kāi),就是在SPREAD宏的定義里,有9的地方使用宏P(guān)P_NARG(__VA_ARGS__)替換一下,于是__VA_ARGS__后面的逗號(hào)可以去掉,也可以簡(jiǎn)化一些代碼了,也能避免展開(kāi)后有你所不希望的多余字符出現(xiàn)。
            測(cè)試考題1:
            定義一宏#define printf,讓它能把printf(str, a, b, c);替換成std::cout<<a<<b<<c<<std::endl;
            參數(shù)個(gè)數(shù)不確定,不用考慮str的內(nèi)容,但假設(shè)不多于10個(gè)參數(shù)

            http://blog.misakamm.org/p/209
            宏的威力還不止至此,當(dāng)宏與C++模板編程結(jié)合的時(shí)候,真正的可怕就來(lái)臨了。。。
            測(cè)試考題2:
            在C++0x之前,模板還沒(méi)有不定參數(shù),于是需要多個(gè)參數(shù)的時(shí)候,不得不手工解決,或者聰明的人,使用模板來(lái)生成多參模板代碼。嘗試一下這么做,看看和之前的問(wèn)題難度加大在哪里。比如生成一個(gè)名為sum的模板函數(shù),能接受1 - 10個(gè)參數(shù),返回這些參數(shù)的相加的結(jié)果

             
             
             
             
             
             
             
             
             
             
             
            文章附帶:
            第一考題參考答案:
            #define BINARY_E0(n, arg) TOSTRING ( arg )
            #define BINARY_E1(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
            "," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
            #define BINARY_E2(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
            "," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
            #define BINARY_E3(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
            "," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
            #define BINARY_E4(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
            "," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
            #define BINARY_E5(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
            "," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
            #define BINARY_E6(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
            "," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
            #define BINARY_E7(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
            "," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
            #define BINARY_E8(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
            "," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
            #define BINARY_ENUM(n) MACROCAT(BINARY_E, n) ( n, )
            #define BIN_0(n, arg) TOSTRING ( arg )
            #define BIN_1(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
            "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
            #define BIN_2(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
            "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
            #define BIN_3(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
            "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
            #define BIN_4(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
            "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
            #define BIN_5(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
            "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
            #define BIN_6(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
            "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
            #define BIN_7(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
            "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
            #define BIN_8(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
            "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
            #define BIN_ENUM(n) "0" MACROCAT(BIN_, n) ( n, )
            測(cè)試代碼:puts(BIN_ENUM(8));
            測(cè)試考題不提供答案。
            

            posted @ 2012-01-16 16:22 御坂美琴 閱讀(7206) | 評(píng)論 (0)編輯 收藏

            2011年12月27日 #

            傻瓜學(xué)習(xí)C語(yǔ)言進(jìn)制轉(zhuǎn)換

            最近受網(wǎng)友的邀請(qǐng),就寫(xiě)一篇入門(mén)的教學(xué)文章。不過(guò)對(duì)于已經(jīng)有一定實(shí)力水平的人來(lái)說(shuō),入門(mén)級(jí)的東西反而對(duì)于他(她)們來(lái)說(shuō)不容易解釋清楚,我也想挑戰(zhàn)一下自己,看看我能把一些基礎(chǔ)問(wèn)題怎么解釋能讓智商80的人也能看明白(雖然這樣說(shuō)有點(diǎn)夸張),所以文章的標(biāo)題就叫做“傻瓜學(xué)習(xí)C語(yǔ)言進(jìn)制轉(zhuǎn)換”,不過(guò)也不是沒(méi)有要求的,要求是,看本文的時(shí)候,請(qǐng)你一定要按順序看,并且要確定你會(huì)寫(xiě)這樣一個(gè)c程序:輸入一個(gè)int,分解出它的個(gè)位,十位,百位(提示:要用’%'求模運(yùn)算和’/'整除運(yùn)算)。。。。。。

            1.數(shù)值與進(jìn)制
            數(shù)值與進(jìn)制是兩個(gè)不同的東西。數(shù)值是什么?100,200這種并不是數(shù)值。
            什么是數(shù)值?古代的時(shí)候,人們記數(shù),有一個(gè)物品就記一塊石頭,或者有11個(gè)物品,就打11個(gè)繩結(jié),這就是數(shù)值,如果你要表示1000,那你還真的需要打1000個(gè)繩結(jié)來(lái)表示。可問(wèn)題就是,這樣子你會(huì)累死,為了不用累死,于是他們發(fā)明了另一種表達(dá)方式:準(zhǔn)備兩種不同的石頭A和B,有一個(gè),那就用一塊A石頭表示,兩個(gè)就用兩塊A表示,如果太多了,比如10個(gè),就用一塊B石頭來(lái)表示有10個(gè)A石頭,比如AAAAABB表示25個(gè)。但是,如果表達(dá)的數(shù)值更大,那就再多準(zhǔn)備一種石頭C,每10個(gè)B石頭就用一個(gè)C石頭來(lái)表示,比如AABCC表示212。于是,這樣就可以大大減少所需要的石頭的數(shù)目,而這,就是進(jìn)制。
            進(jìn)制是數(shù)值的一種表示方式

            2.數(shù)值與進(jìn)制的轉(zhuǎn)化
            進(jìn)制是為了表示一個(gè)數(shù)值,如果是每10個(gè)進(jìn)一,那么就是我們熟悉的10進(jìn)制,否則,如果是每k個(gè)進(jìn)一,那就是k進(jìn)制,比如我們的時(shí)間,是每60秒記1分鐘,這就是60進(jìn)制。然后,怎么把一個(gè)用特定進(jìn)制的表示,得到它的數(shù)值呢?很簡(jiǎn)單,比如上文說(shuō)的AABCC,首先,有兩個(gè)A,分解得AA + BCC,就是2 + BBC,然后,1個(gè)B就是10個(gè)A,于是就是AA + AAAAAAAAAA + AAAAAAAAAA + C,然后一個(gè)C等于10個(gè)B,就是AA + AAAAAAAAAA + AAAAAAAAAA + BBBBBBBBBB,這樣一直拆下去,直到全部是A為止,你就得到實(shí)際的數(shù)值了,實(shí)際的數(shù)值就是A的個(gè)數(shù),記住這一點(diǎn),數(shù)值和進(jìn)制是兩碼事。

            然后,反過(guò)來(lái),怎么把一個(gè)數(shù)值轉(zhuǎn)化為特定進(jìn)制呢?很簡(jiǎn)單,按照進(jìn)制的定義,比如現(xiàn)在有數(shù)值A(chǔ)AAAAAAAAAAAAAAAAAAAAAA,然后,要轉(zhuǎn)成10進(jìn)制,那么我們每10個(gè)分一分組:AAAAAAAAAA + AAAAAAAAAA + AAA,然后,把10個(gè)A用B來(lái)表示,得到:B + B + AAA,如果B有10個(gè),那再把它換成C表示。那么,如果你明白了以上方法,你就得到一個(gè)最基本的進(jìn)制轉(zhuǎn)換手段,就是先化為數(shù)值,再重新用另一個(gè)進(jìn)制表示。比如10進(jìn)制的13,要化成二進(jìn)制,那么,就是BAAA -> AAAAAAAAAAA -> AA AA AA AA AA AA A 這時(shí),換一個(gè)符號(hào),每?jī)蓚€(gè)A用一個(gè)M表示,那么就是MM MM MM A,再每?jī)蓚€(gè)M用一個(gè)N表示,得到NN N A,再每?jī)蓚€(gè)N用一個(gè)P表示,得到P N A。而在這里,一個(gè)P等于8個(gè)A,一個(gè)N等于4個(gè)A,所以P + N + A你可以驗(yàn)算出8 + 4 + 1,等于原來(lái)的數(shù)值。而這種表示方法,就和羅馬數(shù)字很相似,羅馬數(shù)字里,用I表示1,用V表示5,用X表示10,于是18就用XVIII表達(dá),用一個(gè)字母多次重復(fù)來(lái)表達(dá)一個(gè)數(shù)值。

            后來(lái),為了能更方便書(shū)寫(xiě),因?yàn)樽帜笖?shù)量是有限的,無(wú)法表達(dá)更大的數(shù)字,書(shū)寫(xiě)方式改用阿拉伯?dāng)?shù)字寫(xiě)在不同的位置來(lái)表達(dá),于是就是我們今天的10進(jìn)制數(shù)字。比如剛剛的例子,BAAA,有一個(gè)B,于是在十位寫(xiě)1,然后有三個(gè)B,在個(gè)位寫(xiě)3,也就是B的個(gè)數(shù),組合起來(lái)就是13,這是十進(jìn)制的情況。如果是二進(jìn)制,剛剛我們得到的結(jié)果是PNA,注意這里沒(méi)有M,相當(dāng)于0個(gè),而如果我們用二進(jìn)制寫(xiě),那就有四個(gè)位,個(gè)位有一個(gè)A,記1,第二位相當(dāng)于M的個(gè)數(shù),是0,組合起來(lái)是01,第三位是N,記1,組合是101,第四位有一個(gè)P,再組合就是1101,于是這就是10進(jìn)制的13,化為二進(jìn)制的結(jié)果。

            3.進(jìn)制的特點(diǎn)
            問(wèn)你,3638除以10的余數(shù)是多少?給你一秒種思考時(shí)間,多少?如果這個(gè)你不能馬上說(shuō)出來(lái),那你就要反省了。結(jié)果應(yīng)該是8,直接看個(gè)位不就對(duì)了。那么3638除以10的商呢?再給你一秒。。。。。。。。。。。。。。。。。。。這個(gè)答錯(cuò)的話要重讀小學(xué)了,答案當(dāng)然是363.8,如果把這個(gè)數(shù)取整,不要小數(shù)部分,那就是363。小學(xué)的時(shí)候你就應(yīng)該知道,對(duì)一個(gè)數(shù)乘以10或者除以10這種計(jì)算是超簡(jiǎn)單的,因?yàn)槲覀冇玫氖?0進(jìn)制。類似的,問(wèn)一下你,經(jīng)過(guò)60個(gè)5秒是多少分鐘多少秒?再給你一秒思考時(shí)間,要毫不猶豫的回答我。你可別去計(jì)算60*5=300,這是多余的。答案是5分鐘,時(shí)間我們用的60進(jìn)制,那么乘以60只要改一下單位就足夠了,肯定是對(duì)的。再問(wèn)你,10分鐘分成60份是多少秒?你必須立即回答我是10秒。
            我們推廣到任意k進(jìn)制,按這個(gè)特點(diǎn),k進(jìn)制下,乘以k或者除以k的運(yùn)算是超級(jí)簡(jiǎn)單的,比如8進(jìn)制的123,乘以8肯定是1230,除以8就是12.3,相當(dāng)于在移動(dòng)小數(shù)點(diǎn)而已。于是,k進(jìn)制下乘除k就是移動(dòng)小數(shù)點(diǎn)。而除以k求余數(shù)的話,像剛剛的8進(jìn)制的123除以8,就等于12余3,就是要得到個(gè)位上的數(shù)字,同時(shí)得到原來(lái)的數(shù)舍棄掉個(gè)位的結(jié)果。這個(gè)性質(zhì)非常的重要!除法的本質(zhì)是什么?其實(shí)除以k是得到被除數(shù)在k進(jìn)制下的個(gè)位數(shù)(余數(shù)),和小數(shù)點(diǎn)左移的結(jié)果(商)。

            4. C下實(shí)現(xiàn)數(shù)值轉(zhuǎn)化為進(jìn)制
            好,現(xiàn)在回到程序,給你一個(gè)int n,要把它的各位上的數(shù)字取出來(lái),按上面的性質(zhì),那就很簡(jiǎn)單了,先得到個(gè)位,n%10(這個(gè)’%'是求余運(yùn)算),然后小數(shù)點(diǎn)左移,n = n / 10; 然后不斷循環(huán)這個(gè)過(guò)程,如下代碼:

            int n = 2456;
            while (n > 0)
            {
                printf("%d,", n % 10);
                n = n / 10;
            }

            輸出結(jié)果是”6,5,4,2,”,好好領(lǐng)悟一下這段代碼。給你五分鐘時(shí)間。每一次%10就是取出個(gè)位,每一次/10就是丟掉個(gè)位。
            而如果把輸出的結(jié)果里的數(shù)字,逆過(guò)來(lái)看,就是”2456″。

            在這里,那個(gè)int所表示的,就是一個(gè)數(shù)值,剛剛我們的代碼所做的事就是把這個(gè)數(shù)值,一位一位的分解出來(lái)。
            而事實(shí)上,這個(gè)過(guò)程就是把數(shù)值轉(zhuǎn)化為特定進(jìn)制的過(guò)程。剛剛就是把數(shù)值轉(zhuǎn)化為10進(jìn)制。
            如果把剛剛的代碼改為:

            int n = 13;
            while (n > 0)
            {
                printf("%d,", n % 2);
                n = n / 2;
            }

            沒(méi)錯(cuò),輸出結(jié)果是”1,0,1,1″,就是剛剛把13化為二進(jìn)制的例子,每一次%2就是取出二進(jìn)制下的個(gè)位,每一次/2就是丟掉二進(jìn)制下的個(gè)位。
            只要把那個(gè)次序反過(guò)來(lái),就得到1101,就是13化為二進(jìn)制的結(jié)果。在你真正搞明白了除法的本質(zhì)后,那么,數(shù)值轉(zhuǎn)化為以k進(jìn)制表示那是一件很簡(jiǎn)單的事。

            5. 進(jìn)制轉(zhuǎn)化為數(shù)值
            這部分我不打算講,很多人對(duì)這個(gè)比起前面的內(nèi)容來(lái)說(shuō)容易理解很多,直接用進(jìn)制的定義就已經(jīng)很好辦了,沒(méi)什么太難理解的東西。

            6. 作業(yè)
            編寫(xiě)一個(gè)程序,輸入三個(gè)整數(shù)n A B,表示把A進(jìn)制的n,轉(zhuǎn)換為B進(jìn)制,并輸出。
            樣例:
            輸入 輸出
            11 8 10 9
            129 10 2 10000001
            22 3 6 12

            假定輸入的A和B都在2-10這個(gè)范圍,超出范圍的不用去處理,輸入的n保證在int范圍內(nèi)。

            posted @ 2011-12-27 01:41 御坂美琴 閱讀(1450) | 評(píng)論 (1)編輯 收藏

            僅列出標(biāo)題  
            AV色综合久久天堂AV色综合在| 国产成人久久精品麻豆一区| 国产一区二区精品久久凹凸| 久久综合给久久狠狠97色| 欧美成人免费观看久久| 日本久久中文字幕| 午夜精品久久久久| 2020久久精品亚洲热综合一本| 久久久久人妻精品一区三寸蜜桃 | 久久人人爽人人澡人人高潮AV| 久久精品视频网| 久久se这里只有精品| 久久99精品久久久久久野外| 色综合合久久天天给综看| 性做久久久久久久久老女人| 久久久精品国产免大香伊 | 狠狠精品干练久久久无码中文字幕| 嫩草影院久久国产精品| 精品久久久无码中文字幕| 亚洲国产成人乱码精品女人久久久不卡 | 亚洲中文字幕无码久久2017| 久久久久久人妻无码| 日本免费一区二区久久人人澡 | 中文字幕无码av激情不卡久久| 久久久久久久免费视频| 久久精品午夜一区二区福利 | 久久精品综合网| 精品久久久噜噜噜久久久 | 久久九色综合九色99伊人| 成人综合久久精品色婷婷| 久久久无码一区二区三区| 国产精品成人精品久久久| 7777久久久国产精品消防器材| 国产精品久久久久久久| 午夜精品久久久久久久无码| 色偷偷88888欧美精品久久久| 国产精品嫩草影院久久| 日韩久久久久久中文人妻| 久久久久亚洲精品无码网址| 国内精品伊人久久久久av一坑| 国产精品热久久无码av|