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

            大漠落日

            while(!dead) study++;
            posts - 46, comments - 126, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            C Puzzles詳細(xì)分析

            Posted on 2010-05-27 17:04 亂78糟 閱讀(3395) 評(píng)論(11)  編輯 收藏 引用 所屬分類: C語言派系
            極客C Puzzles。
            這里有常見的錯(cuò)誤,也有易混淆的知識(shí)點(diǎn),還有奇妙的算法,更有那些變態(tài)的用法。
            原題目都在這里:http://www.gowrikumar.com/c/,下面詳細(xì)給出我的解答。

            1.sizeof操作符返回值為size_t型,在windows/linux下為typedef size_t unsigned int,而int和unsigned int進(jìn)行比較時(shí),編譯器會(huì)自動(dòng)把int轉(zhuǎn)換為unsigned int,又因?yàn)閕nt d = -1,所以轉(zhuǎn)換之后溢出為正值4294967295,條件不成立。

            2.這道題命很簡(jiǎn)單,仔細(xì)看一下就會(huì)發(fā)現(xiàn)OS_HP-UX_print()中間那個(gè)字符“-”,變量和函數(shù)名只能由字母、數(shù)字還有下劃線組成。

            3.continue語句導(dǎo)致最近的循環(huán)語句的當(dāng)前迭代結(jié)束,執(zhí)行權(quán)被傳遞給條件計(jì)算部分。SO,只會(huì)打印一個(gè)1。

            4.stdout換行緩沖,或者等緩沖區(qū)滿了一并輸出,而stderr無緩沖,即時(shí)輸出,故一開始是看不到hello-out的。

            5.這涉及到一個(gè)宏展開的問題。先來講一下宏展開的步驟,以#define MACRO_TEST(x) x為例,如果宏帶有參數(shù),例如x成為形參,調(diào)用的時(shí)候例如MACRO_TEST(z),那么z則成為實(shí)參:
               第一步,實(shí)參替換形參,帶入宏文本中;
               第二步,如果實(shí)參也是宏,則繼續(xù)展開該實(shí)參宏;
               第三步,繼續(xù)展開宏文本,如果文本中還有宏,繼續(xù)展開,否則宏展開順利結(jié)束。
               上面第一步中,有一個(gè)特例,即字符串化預(yù)處理符#,如果遇到它,停止后面的宏展開,而是把這個(gè)參數(shù)當(dāng)成字符串處理。
            SO,這一題就好解答了。第一個(gè)輸出完全展開宏,為12,而第二個(gè)不完全展開,為f(1,2)。

            6.很簡(jiǎn)單,int和const char怎么比?//錯(cuò)誤
              正確的應(yīng)該是default拼寫錯(cuò)了。。。這個(gè)case語法上是對(duì)的,我理解成語義了,非常感謝網(wǎng)友們的指正。

            7.因?yàn)槲业腜C是32位的,所以無法測(cè)試,google一把,發(fā)現(xiàn)和CPU架構(gòu)有關(guān),IA-64是RISC,不能訪問未對(duì)齊的地址。

            8.和第13題一樣,解法不同,結(jié)果相同。

            9.浮點(diǎn)數(shù)不能直接比較。

            10.int a=1,2;這句被編譯器認(rèn)為是聲明定義變量,而不是逗號(hào)表達(dá)式,2是常量,不能為變量名,非法。

            11.printf返回值是實(shí)際輸出值的個(gè)數(shù),SO,值為4321。

            12.這個(gè)看到register關(guān)鍵字,想來是底層應(yīng)用,google之果然,duff's device,大大的有名。詳細(xì)可以看這個(gè)帖子的鏈接

            13.每次保留那些不是最后一位的1,循環(huán)幾次,就是有幾個(gè)1。這個(gè)函數(shù)針對(duì)unsigned int,其實(shí)對(duì)int也是適用的。

            14、函數(shù)空參數(shù)列表在C語言中表示不定參數(shù),僅有一個(gè)void表示沒有參數(shù),SO,program 1是編譯不過的。注意:C++中給前面兩個(gè)函數(shù)傳參數(shù)都是非法的。

            15、這個(gè)值得好好研究,首先來看一下第一個(gè)輸出匯編代碼(MS V8生成)。
               
                float a = 12.5;
            00411576  fld         dword ptr [__real@41480000 (4156C0h)]   //將立即數(shù)放入浮點(diǎn)寄存器ST0
            0041157C  fstp        dword ptr [a]                           //將ST0中的數(shù)據(jù)放入變量a中 
                printf(
            "%d\n", a);
            0041157F  fld         dword ptr [a]                           //再一次將變量a中的數(shù)據(jù)放入ST0
            00411582  mov         esi,esp                                 //保存棧頂
            00411584  sub         esp,8                                   //調(diào)整棧頂指針ESP,注意這里調(diào)整的是8個(gè)字節(jié),不是float的4個(gè),說明內(nèi)部按double轉(zhuǎn)換了
            00411587  fstp        qword ptr [esp]                         //將ST0中的數(shù)據(jù)入棧
            0041158A  push        offset 
            string "%d\n" (415640h)          //printf函數(shù)參數(shù)入棧
            0041158F  call        dword ptr [__imp__printf (4182B8h)]     //調(diào)用printf
            00411595  add         esp,0Ch                                 //棧頂恢復(fù)
               00411587  fstp        qword ptr [esp]這句代碼之后,我們來看看剛剛?cè)霔5膬?nèi)容,這時(shí)候ESP=0012FE7C,查看內(nèi)存,如下圖

               發(fā)現(xiàn)沒有,頭4個(gè)字節(jié)(紅框部分),printf("%d")打印頭四個(gè)字節(jié),故而輸出為0。
               第二個(gè)輸出就簡(jiǎn)單了,將變量a的數(shù)據(jù)強(qiáng)制為int輸出。

            16、類型T的指針和類型T的數(shù)組并非同種類型,程序試圖寫入0X00000004內(nèi)存,崩潰。詳細(xì)可以參考CCFAQ-0.9.4 ch6.1和ch6.2。

            17、switch跳過第一個(gè)case或default之前的代碼,輸出結(jié)果不定。C++編譯器(G++、VC)是編譯不過的,提示a的初始化被case/default標(biāo)簽跳過了。

            18、數(shù)組做參數(shù)傳遞時(shí)會(huì)退化成指針,函數(shù)void size(int arr[SIZE])等價(jià)于void size(int *arr),輸出為4。

            19、如果傳給Error函數(shù)的參數(shù)字串包含格式化字符串怎么搞?例如,"test123...%d",那么輸出可能為"test123...1245032",大大超出預(yù)期。

            20、輸入a,按回車,輸出a,換行,換行,然后程序結(jié)束。這說明第二個(gè)scanf("%c", &c),這樣不包含空格,直接讀入了回車字符。當(dāng)然,有空格是不讀的。原因?C99 7.19.6.2第五條說的狠清楚:包含空白符的指令從輸入中讀取第一個(gè)非空白符字符,知道無字符可讀。

            21、數(shù)組溢出。

            22、輸出10,4,10,因?yàn)閟izeof操作符實(shí)在編譯時(shí)決定的,里面的i++不會(huì)起作用。
                這里補(bǔ)充一下,sizeof('a')=?,C99中將'a'理解為整形字符常量,為int;C++中為字符字面量,為char。

            23、指針類型不匹配。

            24、不要看到逗號(hào)表達(dá)式就激動(dòng),等號(hào)優(yōu)先級(jí)高于逗號(hào),所以輸出1,不是3。如果改成i=(1,2,3)則是3。

            25、可能死循環(huán)、除數(shù)為0。

            26、不懂,以后有時(shí)間在研究

            27、參考第5題。
              
            28、算法原理,讓兩個(gè)int數(shù)字互掐,直到兩人相等為止。如果是4個(gè)數(shù)求結(jié)果就是4強(qiáng)淘汰賽,分兩隊(duì)互掐,掐完的勝利者再互掐,呵呵。scanf返回的是輸入的字符數(shù)目。

            29、其實(shí)y=y/*p是注釋語句。。。

            30、同20題,scanf讀取非‘-’字符。

            31、scanf("%d\n", &n);

            32、加號(hào)的優(yōu)先級(jí)高于左移運(yùn)算符。

            33、三目運(yùn)算符?:中不能使用return

            34、i--一直小于20,循環(huán)到溢出為止。更改: n--。

            35、ptr2是一個(gè)int型變量,不是指針。聲明指針的最后方法是讓*緊挨著放在變量名前面,例如:int *ptr1, *ptr2。

            36、a沒被初始化就運(yùn)算也就算了,盡然還有除0這種嚴(yán)重錯(cuò)誤。

            37、條件表達(dá)式一旦一個(gè)不成立,立即轉(zhuǎn)到下一個(gè)獨(dú)立條件判斷,匯編碼可以很好的看出。打印8,不是9,也不是7。

            38、指針a已經(jīng)指導(dǎo)最后了,free崩潰。

            39、這個(gè)題目貌似很變態(tài),別怕,還是拿出匯編來看問題。
               printf(&a["ya!hello! how is this ? %s\n"], &b["junk/super"]);
            00413734  mov         eax,dword ptr [b] 
            00413737  add         eax,offset string "junk/super" (415994h) //eax指向string "junk/super"的第5個(gè)字符
            0041373C  mov         esi,esp 
            0041373E  push        eax  
            0041373F  mov         ecx,dword ptr [a] 
            00413742  add         ecx,offset string "ya!hello! how is this ? %s\n" (415A80h) //ecx指向string 的第3個(gè)字符
            00413748  push        ecx  
            00413749  call        dword ptr [__imp__printf (4182B8h)] 
               由匯編碼來分析,其實(shí)相當(dāng)于那一句C代碼等價(jià)于printf("hello! how is this ? %s\n", "super")。
               在來看,說明&b["junk/super"]相當(dāng)于下面的這兩行代碼:
            char arr[] = "junk/super";
            const char *= &arr[b];    
               即數(shù)組a[n]等價(jià)于n[a]。
               第二行printf中的1["this"]其實(shí)等價(jià)于"this"[1],即取出字符'h'。下面在來一次測(cè)試:
            int a[] = {45678};
            int b = 3[a];
            printf(
            "%d\n", b);//輸出7
               原理參考C99 6.5.2.1第二條,E1[E2]的操作下表[]被解析為(*((E1)+(E2))),so,上面的代碼就徹底清楚了。

            40、讀取字符知道遇到a為止,參見C99 7.19.6.2第12條。

            41、a.c中的為聲明,b.c中的為定義,main.c中的為外聯(lián)聲明,需要找定義,所以鏈接b.c中的變量定義,與a.c中的無關(guān)。

            42、閱讀了這題,才明白為什么C那么牛逼。參考 ccfaq-0.9.4 第2.12問。offsetof(struct s, f)計(jì)算s結(jié)構(gòu)中f域的偏移量。

            43、SWAP(a++, b++)。

            44、同第五題。

            45、
            int is_overflow(int *p, int a, int b)
            {
                
            long x, y, z;
                x 
            = (long)a;
                y 
            = (long)b;

                
            *= a + b;

                z 
            = (long)((unsigned long)x + y);
                
            if ( (z^x) >= 0 || (z^b) >= 0 )
                    
            return 1;
                
            else 
                    
            return 0;                   //溢出
            }

            46、看不懂

            47、同43.

            48、起碼為VarArguments(const char *format, ...),可參考printf函數(shù),不定參數(shù)不能只有這一個(gè)...。因?yàn)闃?biāo)準(zhǔn)C要求用可變參數(shù)的函數(shù)至少有一個(gè)固定參數(shù)項(xiàng),這樣才可以使用va_start()。
            補(bǔ)充:標(biāo)準(zhǔn)C++中可以這樣定義,表示0個(gè)或多個(gè)參數(shù),例如void fun(...);函數(shù)void fun(void)和函數(shù)void fun()意思完全一樣,和C不同,見14題。

            49、還真沒想出來。。。

            50、讀取format字符串的長(zhǎng)度存入變量中,例如printf("hello%n", &a),a的值為5。

            51、
            mov eax, [a]
            add eax, [b]

            52、%%

            53、const char *p指向const char的非const指針,char* const p指向char的const指針。

            54、memcopy可以重疊,而后者不可以。

            55、%lf打印double,%f打印float

            56、
            short int a = 0x00ff;
            char *= (char *)&a;
            if (*== 0xff)
               printf(
            "big endia");
            else
               printf(
            "small endia");

            57、
            int main()
            {
               
            if (printf("hello world"< 0)
               {}
            }


            Feedback

            # re: C Puzzles詳細(xì)分析  回復(fù)  更多評(píng)論   

            2010-05-28 12:55 by 凡客誠品襯衫
            路過~~~~~~~~~~·

            # re: C Puzzles詳細(xì)分析  回復(fù)  更多評(píng)論   

            2010-05-28 14:14 by zhangjs
            第六題明顯是default拼錯(cuò),當(dāng)成label了

            # re: C Puzzles詳細(xì)分析  回復(fù)  更多評(píng)論   

            2010-05-28 14:20 by pengwang
            只看第六題你就沒理解C語言,這個(gè)明顯是default拼寫錯(cuò)了,編譯器會(huì)把它當(dāng)成標(biāo)號(hào),而不是int不能和const char比。

            # re: C Puzzles詳細(xì)分析  回復(fù)  更多評(píng)論   

            2010-05-31 09:10 by 亂78糟
            @pengwang
            非常感謝指正錯(cuò)誤,已經(jīng)修正

            # re: C Puzzles詳細(xì)分析  回復(fù)  更多評(píng)論   

            2010-07-18 17:23 by liu zhiquan
            第25個(gè),case '-':
            push(pop() - pop());
            break;
            case '/':
            push(pop() / pop());
            減法、除法和加法、乘法不同,加法和乘法有交換律,不需要考慮函數(shù)調(diào)用的順序。減法和除法不一樣,必須保證第一個(gè)pop()是被減數(shù)或被除數(shù)。

            # re: C Puzzles詳細(xì)分析  回復(fù)  更多評(píng)論   

            2014-03-05 20:23 by lazybug
            第19個(gè)作者已經(jīng)提示了是 Error 函數(shù)定義的問題,Error的參數(shù)應(yīng)該是 const char *,否則const char *類型的字符串不能作為實(shí)參傳遞

            # re: C Puzzles詳細(xì)分析  回復(fù)  更多評(píng)論   

            2014-03-05 20:35 by lazybug
            第25我覺得是 pop() - pop() 的 - 號(hào)兩邊求值順序不確定,結(jié)果可能剛好反過來,同理,/ 也存在這個(gè)問題

            # re: C Puzzles詳細(xì)分析  回復(fù)  更多評(píng)論   

            2014-03-05 20:40 by lazybug
            第27題:
            0001,0010,0100是八進(jìn)制的1, 8, 64

            # re: C Puzzles詳細(xì)分析  回復(fù)  更多評(píng)論   

            2014-03-05 21:43 by lazybug
            第52題也可以 printf("%s", "I can print %");

            # re: C Puzzles詳細(xì)分析  回復(fù)  更多評(píng)論   

            2014-03-05 21:48 by lazybug
            第49題 大概可以用 ?: 運(yùn)算符

            # re: C Puzzles詳細(xì)分析  回復(fù)  更多評(píng)論   

            2014-10-17 11:24 by shuit
            樓主第7題搜的感覺沒說對(duì)點(diǎn)。http://stackoverflow.com/questions/7545365/why-does-this-code-segfault-on-64-bit-architecture-but-work-fine-on-32-bit?rq=1
            stackoverflow上說是以為沒引用頭文件時(shí),malloc的返回值默認(rèn)是int,而在IA64上sizeof(int)和sizeof(int*)不相等,相當(dāng)于沒拿到正確的地址
            精品久久久久久中文字幕| 国产综合久久久久| 91精品国产高清久久久久久91 | 中文字幕久久精品| 国产精品久久久久乳精品爆| 国产精品一区二区久久不卡| 成人午夜精品无码区久久| 2020国产成人久久精品| 人妻丰满?V无码久久不卡| 久久精品无码一区二区三区免费 | 久久99国产精品二区不卡| 男女久久久国产一区二区三区| 99精品久久精品一区二区| 亚洲国产精品无码久久一区二区 | 久久综合久久综合久久| 久久精品成人免费看| 99国内精品久久久久久久| 久久播电影网| 久久久午夜精品| 久久99精品久久久久久动态图| 国产精品久久久久影院嫩草 | 人妻久久久一区二区三区| 久久综合香蕉国产蜜臀AV| 精品999久久久久久中文字幕| 久久免费线看线看| 久久久久国产精品麻豆AR影院| 青草久久久国产线免观| 乱亲女H秽乱长久久久| 国产99久久久久久免费看| 噜噜噜色噜噜噜久久| 久久99精品久久久久子伦| 久久精品无码一区二区三区免费| 噜噜噜色噜噜噜久久| 97精品久久天干天天天按摩| 久久久久久久综合综合狠狠| 狠狠色丁香久久婷婷综合| 精品国产乱码久久久久久1区2区 | 欧美久久亚洲精品| 婷婷久久综合九色综合九七| 久久人人爽人人爽人人AV| 九九久久精品国产|