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

            SEMAN

            曾經滄海難為水、除卻巫山不是云

            C++博客 首頁 新隨筆 聯系 聚合 管理
              9 Posts :: 3 Stories :: 24 Comments :: 0 Trackbacks

            2005年11月30日 #

            [介紹]
            gcc and g++分別是gnu的c & c++編譯器 gcc/g++在執行編譯工作的時候,總共需要4步

            1.預處理,生成.i的文件[預處理器cpp]
            2.將預處理后的文件不轉換成匯編語言,生成文件.s[編譯器egcs]
            3.有匯編變為目標代碼(機器代碼)生成.o的文件[匯編器as]
            4.連接目標代碼,生成可執行程序[鏈接器ld]
            [參數詳解]
            -x language filename
              設定文件所使用的語言,使后綴名無效,對以后的多個有效.也就是根據約定C語言的后
            綴名稱是.c的,而C++的后綴名是.C或者.cpp,如果你很個性,決定你的C代碼文件的后綴
            名是.pig 哈哈,那你就要用這個參數,這個參數對他后面的文件名都起作用,除非到了
            下一個參數的使用。
              可以使用的參數嗎有下面的這些
              `c', `objective-c', `c-header', `c++', `cpp-output', `assembler', and `a
            ssembler-with-cpp'.
              看到英文,應該可以理解的。
              例子用法:
              gcc -x c hello.pig
              
            -x none filename
              關掉上一個選項,也就是讓gcc根據文件名后綴,自動識別文件類型
              例子用法:
              gcc -x c hello.pig -x none hello2.c
              
            -c
              只激活預處理,編譯,和匯編,也就是他只把程序做成obj文件
              例子用法:
              gcc -c hello.c
              他將生成.o的obj文件
            -S
              只激活預處理和編譯,就是指把文件編譯成為匯編代碼。
              例子用法
              gcc -S hello.c
              他將生成.s的匯編代碼,你可以用文本編輯器察看
            -E
              只激活預處理,這個不生成文件,你需要把它重定向到一個輸出文件里面.
              例子用法:
              gcc -E hello.c > pianoapan.txt
              gcc -E hello.c | more
              慢慢看吧,一個hello word 也要與處理成800行的代碼
            -o
              制定目標名稱,缺省的時候,gcc 編譯出來的文件是a.out,很難聽,如果你和我有同感
            ,改掉它,哈哈
              例子用法
              gcc -o hello.exe hello.c (哦,windows用習慣了)
              gcc -o hello.asm -S hello.c
            -pipe
              使用管道代替編譯中臨時文件,在使用非gnu匯編工具的時候,可能有些問題
              gcc -pipe -o hello.exe hello.c
            -ansi
              關閉gnu c中與ansi c不兼容的特性,激活ansi c的專有特性(包括禁止一些asm inl
            ine typeof關鍵字,以及UNIX,vax等預處理宏,
            -fno-asm
              此選項實現ansi選項的功能的一部分,它禁止將asm,inline和typeof用作關鍵字。
                
            -fno-strict-prototype
              只對g++起作用,使用這個選項,g++將對不帶參數的函數,都認為是沒有顯式的對參數
            的個數和類型說明,而不是沒有參數.
              而gcc無論是否使用這個參數,都將對沒有帶參數的函數,認為城沒有顯式說明的類型

              
            -fthis-is-varialble
              就是向傳統c++看齊,可以使用this當一般變量使用.
              
            -fcond-mismatch
              允許條件表達式的第二和第三參數類型不匹配,表達式的值將為void類型
              
            -funsigned-char
            -fno-signed-char
            -fsigned-char
            -fno-unsigned-char
              這四個參數是對char類型進行設置,決定將char類型設置成unsigned char(前兩個參
            數)或者 signed char(后兩個參數)
              
            -include file
              包含某個代碼,簡單來說,就是便以某個文件,需要另一個文件的時候,就可以用它設
            定,功能就相當于在代碼中使用#include<filename>
              例子用法:
              gcc hello.c -include /root/pianopan.h
              
            -imacros file
              將file文件的宏,擴展到gcc/g++的輸入文件,宏定義本身并不出現在輸入文件中
              
            -Dmacro
              相當于C語言中的#define macro
              
            -Dmacro=defn
              相當于C語言中的#define macro=defn
              
            -Umacro
              相當于C語言中的#undef macro
            -undef
              取消對任何非標準宏的定義
              
            -Idir
              在你是用#include"file"的時候,gcc/g++會先在當前目錄查找你所制定的頭文件,如
            果沒有找到,他回到缺省的頭文件目錄找,如果使用-I制定了目錄,他
              回先在你所制定的目錄查找,然后再按常規的順序去找.
              對于#include<file>,gcc/g++會到-I制定的目錄查找,查找不到,然后將到系統的缺
            省的頭文件目錄查找
              
            -I-
              就是取消前一個參數的功能,所以一般在-Idir之后使用
              
            -idirafter dir
              在-I的目錄里面查找失敗,講到這個目錄里面查找.
              
            -iprefix prefix
            -iwithprefix dir
              一般一起使用,當-I的目錄查找失敗,會到prefix+dir下查找
              
            -nostdinc
              使編譯器不再系統缺省的頭文件目錄里面找頭文件,一般和-I聯合使用,明確限定頭
            文件的位置
              
            -nostdin C++
              規定不在g++指定的標準路經中搜索,但仍在其他路徑中搜索,.此選項在創libg++庫
            使用
              
            -C
              在預處理的時候,不刪除注釋信息,一般和-E使用,有時候分析程序,用這個很方便的

              
            -M
              生成文件關聯的信息。包含目標文件所依賴的所有源代碼你可以用gcc -M hello.c
            來測試一下,很簡單。
              
            -MM
              和上面的那個一樣,但是它將忽略由#include<file>造成的依賴關系。
              
            -MD
              和-M相同,但是輸出將導入到.d的文件里面
              
            -MMD
              和-MM相同,但是輸出將導入到.d的文件里面
              
            -Wa,option
              此選項傳遞option給匯編程序;如果option中間有逗號,就將option分成多個選項,然
            后傳遞給會匯編程序
              
            -Wl.option
              此選項傳遞option給連接程序;如果option中間有逗號,就將option分成多個選項,然
            后傳遞給會連接程序.
              
            -llibrary
              制定編譯的時候使用的庫
              例子用法
              gcc -lcurses hello.c
              使用ncurses庫編譯程序
              
            -Ldir
              制定編譯的時候,搜索庫的路徑。比如你自己的庫,可以用它制定目錄,不然
              編譯器將只在標準庫的目錄找。這個dir就是目錄的名稱。
              
            -O0
            -O1
            -O2
            -O3
              編譯器的優化選項的4個級別,-O0表示沒有優化,-O1為缺省值,-O3優化級別最高 
                
            -g
              只是編譯器,在編譯的時候,產生調試信息。
              
            -gstabs
              此選項以stabs格式聲稱調試信息,但是不包括gdb調試信息.
              
            -gstabs+
              此選項以stabs格式聲稱調試信息,并且包含僅供gdb使用的額外調試信息.
              
            -ggdb
              此選項將盡可能的生成gdb的可以使用的調試信息.
            -static
              此選項將禁止使用動態庫,所以,編譯出來的東西,一般都很大,也不需要什么
            動態連接庫,就可以運行.
            -share
              此選項將盡量使用動態庫,所以生成文件比較小,但是需要系統由動態庫.
            -traditional
              試圖讓編譯器支持傳統的C語言特性
            [參考資料]
            -Linux/UNIX高級編程
              中科紅旗軟件技術有限公司編著.清華大學出版社出版
            -Gcc man page
              
            [ChangeLog]
            -2002-08-10
              ver 0.1 發布最初的文檔
            -2002-08-11
              ver 0.11 修改文檔格式
            -2002-08-12
              ver 0.12 加入了對靜態庫,動態庫的參數
            -2002-08-16
              ver 0.16 增加了gcc編譯的4個階段的命令
            運行 gcc/egcs
            **********運行 gcc/egcs***********************
              GCC 是 GNU 的 C 和 C++ 編譯器。實際上,GCC 能夠編譯三種語言:C、C++ 和 O
            bject C(C 語言的一種面向對象擴展)。利用 gcc 命令可同時編譯并連接 C 和 C++
            源程序。
              如果你有兩個或少數幾個 C 源文件,也可以方便地利用 GCC 編譯、連接并生成可
            執行文件。例如,假設你有兩個源文件 main.c 和 factorial.c 兩個源文件,現在要編
            譯生成一個計算階乘的程序。
            代碼:
            -----------------------
            清單 factorial.c
            -----------------------
            int factorial (int n)
            {
              if (n <= 1)
               return 1;
              else
               return factorial (n - 1) * n;
            }
            -----------------------
            清單 main.c
            -----------------------
            #include <stdio.h>
            #include <unistd.h>
            int factorial (int n);
            int main (int argc, char **argv)
            {
              int n;
              if (argc < 2)
              {
                printf ("Usage: %s n\n", argv [0]);
                return -1;
              }
              else
              {
               n = atoi (argv[1]);
               printf ("Factorial of %d is %d.\n", n, factorial (n));
               }
              return 0;
            }
            -----------------------
            利用如下的命令可編譯生成可執行文件,并執行程序:
            $ gcc -o factorial main.c factorial.c
            $ ./factorial 5
            Factorial of 5 is 120.
              GCC 可同時用來編譯 C 程序和 C++ 程序。一般來說,C 編譯器通過源文件的后綴
            名來判斷是 C 程序還是 C++ 程序。在 Linux 中,C 源文件的后綴名為 .c,而 C++ 源
            文件的后綴名為 .C 或 .cpp。但是,gcc 命令只能編譯 C++ 源文件,而不能自動和 C
            ++ 程序使用的庫連接。因此,通常使用 g++ 命令來完成 C++ 程序的編譯和連接,該程
            序會自動調用 gcc 實現編譯。假設我們有一個如下的 C++ 源文件(hello.C):
            #include <iostream>
            void main (void)
            {
              cout << "Hello, world!" << endl;
            }
            則可以如下調用 g++ 命令編譯、連接并生成可執行文件:
            $ g++ -o hello hello.C
            $ ./hello
            Hello, world!
            **********************gcc/egcs 的主要選項*********
            gcc 命令的常用選項
            選項 解釋
            -ansi 只支持 ANSI 標準的 C 語法。這一選項將禁止 GNU C 的某些特色,
            例如 asm 或 typeof 關鍵詞。
            -c 只編譯并生成目標文件。
            -DMACRO 以字符串“1”定義 MACRO 宏。
            -DMACRO=DEFN 以字符串“DEFN”定義 MACRO 宏。
            -E 只運行 C 預編譯器。
            -g 生成調試信息。GNU 調試器可利用該信息。
            -IDIRECTORY 指定額外的頭文件搜索路徑DIRECTORY。
            -LDIRECTORY 指定額外的函數庫搜索路徑DIRECTORY。
            -lLIBRARY 連接時搜索指定的函數庫LIBRARY。
            -m486 針對 486 進行代碼優化。
            -o FILE 生成指定的輸出文件。用在生成可執行文件時。
            -O0 不進行優化處理。
            -O 或 -O1 優化生成代碼。
            -O2 進一步優化。
            -O3 比 -O2 更進一步優化,包括 inline 函數。
            -shared 生成共享目標文件。通常用在建立共享庫時。
            -static 禁止使用共享連接。
            -UMACRO 取消對 MACRO 宏的定義。
            -w 不生成任何警告信息。
            -Wall 生成所有警告信息。
            posted @ 2005-11-30 13:36 味全每日C++ 閱讀(75258) | 評論 (3)編輯 收藏


            Author:sungo
            (TW@Javaworld)  文章原文:http://www.javaworld.com.tw/jute/post/view?bid=10&id=53262&sty=1&tpg=1&age=0

            Eclipse除了可以開發Java之外,還支援了許多語言,現在先介紹
            C、C++的開發環境設定,以後有機會再介紹其它的。Enjoy it!

            OS:Windows XP Professional SP1
            使用版本:Eclipse 2.1.2

            一.首先要下載CDT,Eclipse 2.1.2使用者,請下載這項:
            CDT 1.2 Full for Windows R2.1.1 1.2.0 GA - Full - Windows。
            Eclipse 2.1.3使用者請下載:CDT 1.2.1。
            Eclipse 3.0 M7使用者請下載:CDT 2.0 M7。
            Eclipse 3.0 M8使用者請下載:CDT 2.0 M8。
            Eclipse 3.0 M9使用者請下載:CDT 2.0 M9。
            下載網址:
            http://www.eclipse.org/cdt/

            安裝:將解壓縮後的features、plugins整個資料夾複製到Eclipse安裝資料
            裡,重新開啟Eclipse即可。

            二.下載可在Windows上使用的GNU C、C++編譯器,這裡要下載的是:MinGW。
            Download頁面很長的一串,請選擇這個版本:
            MinGW bin MinGW-3.1.0-1.exe 14863 kb Sep 15, 2003 11:14
            下載網址:
            http://www.mingw.org/download.shtml

            安裝:安裝目錄選C槽,然後狂點下一步(Next)就行了。安裝完後路徑是這
            樣->C:\MinGW。

            三.先在Command Line模式下測試編譯與執行。先將C:\MinGW\bin底下的
            mingw32-make.exe更名為make.exe,因為待會在Eclipse使用時它預設
            會抓系統裡make這個檔名而不是mingw32-make。

            (註:如果不更名或是還有其他make程式時,也可以在稍後的Eclipse設定
            中,在make targets view的地方,新增一個task時,build command 取消
            use default , 使用 mingw32-make,或在project properties->make project ->
            將make 改為 mingw32-make )
            -- 由 snpshu 補充。

            在環境變數裡加入下列設定:
            PATH : C:\MinGW\bin; (如果系統已經有裝其它C/C++編譯器,請把C:\MinGW\bin加在最前面。)
            LIBRARY_PATH :C:\MinGW\lib
            C_INCLUDE_PATH :C:\MinGW\include
            CPLUS_INCLUDE_PATH :C:\MinGW\include\c++\3.2.3;C:\MinGW\include\c++\3.2.3\mingw32;
            C:\MinGW\include\c++\3.2.3\backward;C:\MinGW\include

            先使用文字編輯器編寫測試用的原始檔,檔名:main.cpp。
            1
            2
            3
            4
            5
            6
            7
            8
            #include <iostream>
            using namespace std;
             
            int main(void) {
                cout << "Can You Feel My World?" ;
             
                return 0;
            }

            在Command Line下編譯指令:
            1
            C:\g++ main.cpp -O3 -o hello

            (O3的O是英文大寫"歐")
            編譯成功後:便會產生hello.exe的執行檔。
            執行畫面如下:
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            Microsoft Windows XP [版本 5.1.2600]
            (C) Copyright 1985-2001 Microsoft Corp.
             
            C:\Documents and Settings\Sungo>cd\
             
            C:\>g++ main.cpp -O3 -o hello
             
            C:\>hello
            Can You Feel My World?
            C:\>
            

            註:-O3 旗標表示採最高級編譯最佳化,編譯速度最慢,但產生的執行檔
            檔案會最小,執行速度會最快;-o 旗標表示將編譯完的*.exe重新更名。

            ◎步驟一.開啟Eclipse後,首先先開啟C/C++專用視景。
            Windows->Open Perspective->C/C++ Development

            ◎步驟二.建立一個C++用的專案。
            File-New->Project->C++->Standard Make C++ Project
            (接下來的步驟跟建立一般的Java專案一樣,皆採預設即可)

            ◎步驟三.把我們剛剛寫的main.cpp import進來,加到專案裡。
            File->Import->File System->瀏覽C:\main.cpp

            ◎步驟四.建立一個makefile。
            File->New->File,檔案名稱填:makefile。(不需打副檔名)

            makefile內容如下:
            1
            2
            all:
                g++  main.cpp -g -o run
            

            注意:makefile縮排要以Tab鍵作縮排,不能以空格4作縮排,
            否則Build會有問題。


            ◎步驟五.設定Make Targets。
            Windows-Show View->Make Targets
            在Make Targets視窗裡按滑鼠右鍵,Add Build Target
            ,name打:編譯。Build Target打:all。

            ◎步驟六.編譯。
            在剛剛建立的Make Targets "編譯" 上點滑鼠2下,即會開始編譯,
            此時我們可以發現hello.exe已經產生在我們專案下了??稍诘紫?
            C-Build視窗看到以下輸出結果:
            1
            2
            make -k all 
            g++  main.cpp -g -o run
            


            ◎步驟七. *.exe執行前設定。因為在Windows下Run,所以要先作個設定
            ,請開啟Project->Properties->C/C++ Make Project->Binary Parser頁面。
            Binary Parser下拉式選單,將ELF Parser改成PE Windows Parser。

            ◎步驟八.執行。
            Run->Run as->C Local Application。
            在底下Consloe視窗看到hello.exe的執行結果。

            註:當原始檔有修改,要重新編譯時,只要滑鼠雙擊我們在步驟五
            所建立的Make Targets "編譯",即可Rebuilding。

            posted @ 2005-11-30 12:57 味全每日C++ 閱讀(1520) | 評論 (0)編輯 收藏

            2005年11月23日 #

            預處理器(Preprocessor)


            1. 用預處理指令#define 聲明一個常數,用以表明1年中有多少秒(忽略閏年問題)

            #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
            我在這想看到幾件事情:
            1). #define 語法的基本知識(例如:不能以分號結束,括號的使用,等等)
            2). 懂得預處理器將為你計算常數表達式的值,因此,直接寫出你是如何計算一年中有多少秒而不是計算出實際的值,是更清晰而沒有代價的。
            3). 意識到這個表達式將使一個16位機的整型數溢出-因此要用到長整型符號L,告訴編譯器這個常數是的長整型數。
            4). 如果你在你的表達式中用到UL(表示無符號長整型),那么你有了一個好的起點。記住,第一印象很重要。


            2. 寫一個“標準”宏MIN,這個宏輸入兩個參數并返回較小的一個。

            #define MIN(A,B) ((A) <= (B) (A) : (B))
            這個測試是為下面的目的而設的:
            1). 標識#define在宏中應用的基本知識。這是很重要的,因為直到嵌入(inline)操作符變為標準C的一部分,宏是方便產生嵌入代碼的唯一方法,對于嵌入式系統來說,為了能達到要求的性能,嵌入代碼經常是必須的方法。
            2). 三重條件操作符的知識。這個操作符存在C語言中的原因是它使得編譯器能產生比if-then-else更優化的代碼,了解這個用法是很重要的。
            3). 懂得在宏中小心地把參數用括號括起來
            4). 我也用這個問題開始討論宏的副作用,例如:當你寫下面的代碼時會發生什么事?
            least = MIN(*p++, b);


            3. 預處理器標識#error的目的是什么?

            如果你不知道答案,請看參考文獻1。這問題對區分一個正常的伙計和一個書呆子是很有用的。只有書呆子才會讀C語言課本的附錄去找出象這種
            問題的答案。當然如果你不是在找一個書呆子,那么應試者最好希望自己不要知道答案。


            死循環(Infinite loops)


            4. 嵌入式系統中經常要用到無限循環,你怎么樣用C編寫死循環呢?

            這個問題用幾個解決方案。我首選的方案是:
            while(1) { }
            一些程序員更喜歡如下方案:
            for(;;) { }
            這個實現方式讓我為難,因為這個語法沒有確切表達到底怎么回事。如果一個應試者給出這個作為方案,我將用這個作為一個機會去探究他們這樣做的
            基本原理。如果他們的基本答案是:“我被教著這樣做,但從沒有想到過為什么?!边@會給我留下一個壞印象。
            第三個方案是用 goto
            Loop:
            ...
            goto Loop;
            應試者如給出上面的方案,這說明或者他是一個匯編語言程序員(這也許是好事)或者他是一個想進入新領域的BASIC/FORTRAN程序員。

            數據聲明(Data declarations)

            5. 用變量a給出下面的定義
            a) 一個整型數(An integer)
            b) 一個指向整型數的指針(A pointer to an integer)
            c) 一個指向指針的的指針,它指向的指針是指向一個整型數(A pointer to a pointer to an integer)
            d) 一個有10個整型數的數組(An array of 10 integers)
            e) 一個有10個指針的數組,該指針是指向一個整型數的(An array of 10 pointers to integers)
            f) 一個指向有10個整型數數組的指針(A pointer to an array of 10 integers)
            g) 一個指向函數的指針,該函數有一個整型參數并返回一個整型數(A pointer to a function that takes an integer as an argument and returns an integer)
            h) 一個有10個指針的數組,該指針指向一個函數,該函數有一個整型參數并返回一個整型數( An array of ten pointers to functions that take an integer argument and return an integer )

            答案是:
            a) int a; // An integer
            b) int *a; // A pointer to an integer
            c) int **a; // A pointer to a pointer to an integer
            d) int a[10]; // An array of 10 integers
            e) int *a[10]; // An array of 10 pointers to integers
            f) int (*a)[10]; // A pointer to an array of 10 integers
            g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
            h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer


            人們經常聲稱這里有幾個問題是那種要翻一下書才能回答的問題,我同意這種說法。當我寫這篇文章時,為了確定語法的正確性,我的確查了一下書。
            但是當我被面試的時候,我期望被問到這個問題(或者相近的問題)。因為在被面試的這段時間里,我確定我知道這個問題的答案。應試者如果不知道
            所有的答案(或至少大部分答案),那么也就沒有為這次面試做準備,如果該面試者沒有為這次面試做準備,那么他又能為什么出準備呢?


            Static

            6. 關鍵字static的作用是什么?

            這個簡單的問題很少有人能回答完全。在C語言中,關鍵字static有三個明顯的作用:
            1). 在函數體,一個被聲明為靜態的變量在這一函數被調用過程中維持其值不變。
            2). 在模塊內(但在函數體外),一個被聲明為靜態的變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問。它是一個本地的全局變量。
            3). 在模塊內,一個被聲明為靜態的函數只可被這一模塊內的其它函數調用。那就是,這個函數被限制在聲明它的模塊的本地范圍內使用。
            大多數應試者能正確回答第一部分,一部分能正確回答第二部分,同是很少的人能懂得第三部分。這是一個應試者的嚴重的缺點,因為他顯然不懂得本地化數據和代碼范圍的好處和重要性。


            Const

            7.關鍵字const是什么含意?
            我只要一聽到被面試者說:“const意味著常數”,我就知道我正在和一個業余者打交道。去年Dan Saks已經在他的文章里完全概括了const的所有用法,因此ESP(譯者:Embedded Systems Programming)的每一位讀者應該非常熟悉const能做什么和不能做什么.如果你從沒有讀到那篇文章,只要能說出const意味著“只讀”就可以了。盡管這個答案不是完全的答案,但我接受它作為一個正確的答案。(如果你想知道更詳細的答案,仔細讀一下Saks的文章吧。)如果應試者能正確回答這個問題,我將問他一個附加的問題:下面的聲明都是什么意思?

            const int a;
            int const a;
            const int *a;
            int * const a;
            int const * a const;

            前兩個的作用是一樣,a是一個常整型數。第三個意味著a是一個指向常整型數的指針(也就是,整型數是不可修改的,但指針可以)。第四個意思a是一個指向整型數的常指針(也就是說,指針指向的整型數是可以修改的,但指針是不可修改的)。最后一個意味著a是一個指向常整型數的常指針(也就是說,指針指向的整型數是不可修改的,同時指針也是不可修改的)。如果應試者能正確回答這些問題,那么他就給我留下了一個好印象。順帶提一句,也許你可能會問,即使不用關鍵字const,也還是能很容易寫出功能正確的程序,那么我為什么還要如此看重關鍵字const呢?我也如下的幾下理由:
            1). 關鍵字const的作用是為給讀你代碼的人傳達非常有用的信息,實際上,聲明一個參數為常量是為了告訴了用戶這個參數的應用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學會感謝這點多余的信息。(當然,懂得用const的程序員很少會留下的垃圾讓別人來清理的。)
            2). 通過給優化器一些附加的信息,使用關鍵字const也許能產生更緊湊的代碼。
            3). 合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現。

            Volatile

            8. 關鍵字volatile有什么含意 并給出三個不同的例子。

            一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器里的備份。下面是volatile變量的幾個例子:
            1). 并行設備的硬件寄存器(如:狀態寄存器)
            2). 一個中斷服務子程序中會訪問到的非自動變量(Non-automatic variables)
            3). 多線程應用中被幾個任務共享的變量
            回答不出這個問題的人是不會被雇傭的。我認為這是區分C程序員和嵌入式系統程序員的最基本的問題。嵌入式系統程序員經常同硬件、中斷、RTOS等等打交道,所用這些都要求volatile變量。不懂得volatile內容將會帶來災難。
            假設被面試者正確地回答了這是問題(嗯,懷疑這否會是這樣),我將稍微深究一下,看一下這家伙是不是直正懂得volatile完全的重要性。
            1). 一個參數既可以是const還可以是volatile嗎?解釋為什么。
            2). 一個指針可以是volatile 嗎?解釋為什么。
            3). 下面的函數有什么錯誤:
            int square(volatile int *ptr)
            {
            return *ptr * *ptr;
            }
            下面是答案:
            1). 是的。一個例子是只讀的狀態寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應該試圖去修改它。
            2). 是的。盡管這并不很常見。一個例子是當一個中服務子程序修該一個指向一個buffer的指針時。
            3). 這段代碼的有個惡作劇。這段代碼的目的是用來返指針*ptr指向值的平方,但是,由于*ptr指向一個volatile型參數,編譯器將產生類似下面的代碼:
            int square(volatile int *ptr)
            {
            int a,b;
            a = *ptr;
            b = *ptr;
            return a * b;
            }
            由于*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:
            long square(volatile int *ptr)
            {
            int a;
            a = *ptr;
            return a * a;
            }

            位操作(Bit manipulation)

            9. 嵌入式系統總是要用戶對變量或寄存器進行位操作。給定一個整型變量a,寫兩段代碼,第一個設置a的bit 3,第二個清除a 的bit 3。在以上兩個操作中,要保持其它位不變。

            對這個問題有三種基本的反應
            1). 不知道如何下手。該被面者從沒做過任何嵌入式系統的工作。
            2). 用bit fields。Bit fields是被扔到C語言死角的東西,它保證你的代碼在不同編譯器之間是不可移植的,同時也保證了的你的代碼是不可重用的。我最近不幸看到Infineon為其較復雜的通信芯片寫的驅動程序,它用到了bit fields因此完全對我無用,因為我的編譯器用其它的方式來實現bit fields的。從道德講:永遠不要讓一個非嵌入式的家伙粘實際硬件的邊。
            3). 用 #defines 和 bit masks 操作。這是一個有極高可移植性的方法,是應該被用到的方法。最佳的解決方案如下:
            #define BIT3 (0x1<<3)
            static int a;
            void set_bit3(void)
            {
            a |= BIT3;
            }
            void clear_bit3(void)
            {
            a &= ~BIT3;
            }
            一些人喜歡為設置和清除值而定義一個掩碼同時定義一些說明常數,這也是可以接受的。我希望看到幾個要點:說明常數、|=和&=~操作。

            訪問固定的內存位置(Accessing fixed memory locations)

            10. 嵌入式系統經常具有要求程序員去訪問某特定的內存位置的特點。在某工程中,要求設置一絕對地址為0x67a9的整型變量的值為0xaa66。編譯器是一個純粹的ANSI編譯器。寫代碼去完成這一任務。

            這一問題測試你是否知道為了訪問一絕對地址把一個整型數強制轉換(typecast)為一指針是合法的。這一問題的實現方式隨著個人風格不同而不同。典型的類似代碼如下:
            int *ptr;
            ptr = (int *)0x67a9;
            *ptr = 0xaa55;

            一個較晦澀的方法是:
            *(int * const)(0x67a9) = 0xaa55;

            即使你的品味更接近第二種方案,但我建議你在面試時使用第一種方案。

            中斷(Interrupts)

            11. 中斷是嵌入式系統中重要的組成部分,這導致了很多編譯開發商提供一種擴展—讓標準C支持中斷。具代表事實是,產生了一個新的關鍵字__interrupt。下面的代碼就使用了__interrupt關鍵字去定義了一個中斷服務子程序(ISR),請評論一下這段代碼的。

            __interrupt double compute_area (double radius)
            {
                double area = PI * radius * radius;
                printf(" Area = %f", area);
                return area;
            }

            這個函數有太多的錯誤了,以至讓人不知從何說起了:
            1). ISR 不能返回一個值。如果你不懂這個,那么你不會被雇用的。
            2). ISR 不能傳遞參數。如果你沒有看到這一點,你被雇用的機會等同第一項。
            3). 在許多的處理器/編譯器中,浮點一般都是不可重入的。有些處理器/編譯器需要讓額處的寄存器入棧,有些處理器/編譯器就是不允許在ISR中做浮點運算。此外,ISR應該是短而有效率的,在ISR中做浮點運算是不明智的。
            4). 與第三點一脈相承,printf()經常有重入和性能上的問題。如果你丟掉了第三和第四點,我不會太為難你的。不用說,如果你能得到后兩點,那么你的被雇用前景越來越光明了。

            代碼例子(Code examples)
            12 . 下面的代碼輸出是什么,為什么?

            void foo(void)
            {
                unsigned int a = 6;
                int b = -20;
                (a+b > 6) puts("> 6") : puts("<= 6");
            }

            這個問題測試你是否懂得C語言中的整數自動轉換原則,我發現有些開發者懂得極少這些東西。不管如何,這無符號整型問題的答案是輸出是“>6”。原因是當表達式中存在有符號類型和無符號類型時所有的操作數都自動轉換為無符號類型。 因此-20變成了一個非常大的正整數,所以該表達式計算出的結果大于6。這一點對于應當頻繁用到無符號數據類型的嵌入式系統來說是豐常重要的。如果你答錯了這個問題,你也就到了得不到這份工作的邊緣。

            13. 評價下面的代碼片斷:

            unsigned int zero = 0;
            unsigned int compzero = 0xFFFF;
            /*1's complement of zero */

            對于一個int型不是16位的處理器為說,上面的代碼是不正確的。應編寫如下:

            unsigned int compzero = ~0;

            這一問題真正能揭露出應試者是否懂得處理器字長的重要性。在我的經驗里,好的嵌入式程序員非常準確地明白硬件的細節和它的局限,然而PC機程序往往把硬件作為一個無法避免的煩惱。
            到了這個階段,應試者或者完全垂頭喪氣了或者信心滿滿志在必得。如果顯然應試者不是很好,那么這個測試就在這里結束了。但如果顯然應試者做得不錯,那么我就扔出下面的追加問題,這些問題是比較難的,我想僅僅非常優秀的應試者能做得不錯。提出這些問題,我希望更多看到應試者應付問題的方法,而不是答案。不管如何,你就當是這個娛樂吧…



            動態內存分配(Dynamic memory allocation)



            14. 盡管不像非嵌入式計算機那么常見,嵌入式系統還是有從堆(heap)中動態分配內存的過程的。那么嵌入式系統中,動態分配內存可能發生的問題是什么?

            這里,我期望應試者能提到內存碎片,碎片收集的問題,變量的持行時間等等。這個主題已經在ESP雜志中被廣泛地討論過了(主要是 P.J. Plauger, 他的解釋遠遠超過我這里能提到的任何解釋),所有回過頭看一下這些雜志吧!讓應試者進入一種虛假的安全感覺后,我拿出這么一個小節目:下面的代碼片段的輸出是什么,為什么?

            char *ptr;
            if ((ptr = (char *)malloc(0)) == NULL)
            puts("Got a null pointer");
            else
            puts("Got a valid pointer");

            這是一個有趣的問題。最近在我的一個同事不經意把0值傳給了函數malloc,得到了一個合法的指針之后,我才想到這個問題。這就是上面的代碼,該代碼的輸出是“Got a valid pointer”。我用這個來開始討論這樣的一問題,看看被面試者是否想到庫例程這樣做是正確。得到正確的答案固然重要,但解決問題的方法和你做決定的基本原理更重要些。

            Typedef

            15. Typedef 在C語言中頻繁用以聲明一個已經存在的數據類型的同義字。也可以用預處理器做類似的事。例如,思考一下下面的例子:
            #define dPS struct s *
            typedef struct s * tPS;

            以上兩種情況的意圖都是要定義dPS 和 tPS 作為一個指向結構s指針。哪種方法更好呢?(如果有的話)為什么?
            這是一個非常微妙的問題,任何人答對這個問題(正當的原因)是應當被恭喜的。答案是:typedef更好。思考下面的例子:
            dPS p1,p2;
            tPS p3,p4;

            第一個擴展為
            struct s * p1, p2;

            上面的代碼定義p1為一個指向結構的指,p2為一個實際的結構,這也許不是你想要的。第二個例子正確地定義了p3 和p4 兩個指針。

            晦澀的語法

            16. C語言同意一些令人震驚的結構,下面的結構是合法的嗎,如果是它做些什么?
            int a = 5, b = 7, c;
            c = a+++b;

            這個問題將做為這個測驗的一個愉快的結尾。不管你相不相信,上面的例子是完全合乎語法的。問題是編譯器如何處理它?水平不高的編譯作者實際上會爭論這個問題,根據最處理原則,編譯器應當能處理盡可能所有合法的用法。因此,上面的代碼被處理成:
            c = a++ + b;
            因此, 這段代碼持行后a = 6, b = 7, c = 12。
            如果你知道答案,或猜出正確答案,做得好。如果你不知道答案,我也不把這個當作問題。我發現這個問題的最大好處是:這是一個關于代碼編寫風格,代碼的可讀性,代碼的可修改性的好的話題

            posted @ 2005-11-23 20:25 味全每日C++ 閱讀(9802) | 評論 (3)編輯 收藏

            2005年11月22日 #

            地址:http://www.topcoder.com/pl/?module=Static&d1=gccj05&d2=ZH_overview

            Google? Code Jam - 中國編程挑戰賽
            ?
            English Version
             
            重要日期

            報名開始
            11月21日星期一

            入圍賽
            12月12日星期一

            總決賽
            1月20日星期五
             
            價值25萬元的
            高科技獎品


            你有用技術改變世界的夢想嗎?你有挑戰難度的決心嗎?你想和國內計算機精英一決高下嗎?全球編程界知名的“Google編程挑戰賽Code Jam”即將登陸中國。這項比賽每年都是全球計算機界的一次盛事。今年 Google 首次專門為中國舉辦這項比賽,旨在弘揚計算機科學的藝術,推進中國計算機編程教育,鼓勵并嘉獎中國頂級編程人才。

            競賽的題目具有相當的挑戰性,競賽獎品也非常豐厚。 有志之士可借此機會一展才能,成為脫穎而出的中國最佳。

            這里有極富挑戰性的題目,高科技的獎品,以及令人贊嘆的榮耀,你還在等什么?

            賽事運作細則

            此次挑戰賽以計時賽的形式舉行,所有的參賽者都將在限定的時間內在線完成相同的競賽題目。

            參賽者在競賽過程當中,可以選用以下4種編程語言的一種-Java,C++,C#和VB。

            以下是競賽相關過程說明:

            下載競賽平臺
            參賽者將從TopCoder?公司的競賽平臺(一個Java程序)開始踏入競賽的第一步。下載平臺程序,仔細閱讀競賽題目,然后將解決方案編寫成代碼形式,編譯并測試方案,最后提交方案代碼,得到相應的分數。參賽者可以在正式競賽前下載競賽平臺,通過提供的樣例來體驗和熟悉平臺的操作環境。

            編碼階段
            在指定的日期和時間,參賽者進入競賽平臺,以每10人一組被安排進入相應的虛擬房間。所有參賽者都將獲得相同的3道競賽題,3題的難度遞增。此階段競賽中,競賽者須在最短時間內完成題目,提供正確的方案代碼,代碼提交得越早,競賽者得到的分數越高。在競賽的整個過程中,排名榜會顯示競賽者的累計分數。

            挑戰階段
            在挑戰階段,參賽者不但可以看到其他參賽者提交的方案代碼,還可以給出測試數據,使其他參賽者提交的程序得到錯誤的運算結果,從而推翻其他參賽者所提交的方案。這種方式,對于編程人員來說是最直接的競賽形式。在這個階段,參賽者的測試數據若能成功推翻他人提交的代碼則可得分;反之,將被扣分。

            系統測試
            在系統測試階段,系統會自動對每個提交方案代碼進行測試,確定其正確程度和可行性,并以此給出參賽者相應的分數。整個評測過程耗時很短,參賽者當場可以知道自己的比賽結果。

            參賽須知

            報名注冊時間:從北京時間2005年11月21日星期一上午9時開始,至北京時間2005年12月12日上午9時結束。報名注冊沒有人數限制,但是只有通過資格賽的前500名(12月12日舉行)可以晉級此次正式比賽的第一輪。第一輪比賽將在12月19日舉行。

            首輪名次前250名將于12月22日晉級第二輪,第二輪的前50名則將參加在中國舉行的冠軍賽,爭奪總數達25萬元的高額獎品。

            日期 時間 * 狀態
            11月21日星期一 9:00 注冊開始
            12月12日星期一 9:00 注冊結束
            12月12日星期一 12:00 資格賽開始
            12月13日星期二 12:00 資格賽結束
            12月19日星期一 21:00 第一輪-500名參賽者
            12月22日星期四 21:00 第二輪-250名參賽者
            1月20日星期五 待定 冠軍賽-50名參賽者
            * 上述時間皆為北京時間。冠軍賽日期有可能發生變化,請注意屆時通知。


            獎品

            晉級第二輪的250名參賽者將獲贈"Google? Code Jam - 中國編程挑戰賽"T恤一件和李開復博士撰寫并簽名的《做最好的自己》一書。晉級冠軍賽的50名參賽者將獲得如下的獎項:

            參賽者 獎品
            第1名 (共價值40,000人民幣) 一組高端個人編程工作站
            第2至第4名 (每位獎品價值20,000人民幣) 一臺筆記本電腦, PDA手機, 以及一款全新個人隨身聽
            第5至10名(每位獎品價值8,000人民幣) 一臺數字相機,PDA手機, 以及一款全新個人隨身聽
            第11至20名(每位獎品價值4,000人民幣) PDA手機, 以及一款全新個人隨身聽
            第21至50名 (每位獎品價值2,000人民幣) 一款全新個人隨身聽
            posted @ 2005-11-22 14:57 味全每日C++ 閱讀(874) | 評論 (0)編輯 收藏

            2005年11月21日 #

            Introduction   http://www.codeproject.com/cpp/bitbashing.asp

            I have noticed that some people seem to have problems with bitwise operators, so I decided to write this brief tutorial on how to use them.

            An Introduction to bits

            Bits, what are they you may ask?

            Well, simply put, bits are the individual ones and zeros that make up every thing we do with computers. All the data you use is stored in your computer using bits. A BYTE is made up of eight bits, a WORD is two BYTEs, or sixteen bits. And a DWORD is two WORDS, or thirty two bits.

             0 1 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 1 1 1 0 1 0 0 0 1 1 1 1 0 0 0
            ||                  |                   |                    |                  ||
            |+- bit 31       |                    |                    |         bit 0 -+|
            |                   |                    |                    |                   |
            +-- BYTE 3 ---+--- BYTE 2 ---+--- BYTE 1 ---+-- BYTE 0 ---+
            |                                        |                                         |
            +----------- WORD 1 --------+----------- WORD 0 ---------+
            |                                                                                  |
            +--------------------------- DWORD -----------------------+
            

            The beauty of having bitwise operators is that you can use a BYTE, WORD or DWORD as a small array or structure. Using bitwise operators you can check or set the values of individual bits or even a group of bits.

            Hexadecimal numbers and how they relate to bits

            When working with bits, it is kind of hard to express every number using just ones and zeros, which is known as binary notation. To get around this we use hexadecimal (base 16) numbers.

            As you may or may not know, it takes four bits to cover all the numbers from zero to fifteen, which also happens to be the range of a single digit hexadecimal number. This group of four bits, or half a BYTE, is called a nibble. As there are two nibbles in a BYTE, we can use two hexadecimal digits to show the value of one BYTE.

            NIBBLE   HEX VALUE
            ======   =========
             0000        0
             0001        1
             0010        2
             0011        3
             0100        4
             0101        5
             0110        6
             0111        7
             1000        8
             1001        9
             1010        A
             1011        B
             1100        C
             1101        D
             1110        E
             1111        F

            So if we had one BYTE containing the letter 'r' (ASCII code 114) it would look like this:

            0111 0010    binary
              7    2     hexadecimal

            We could write it as '0x72'

            Bitwise operators

            There are six bitwise operators. They are:
               &   The AND operator
               |   The OR operator
               ^   The XOR operator
               ~   The Ones Complement or Inversion operator
              >>   The Right Shift operator
              <<   The Left Shift operator.

            The & operator

            The & (AND) operator compares two values, and returns a value that has its bits set if, and only if, the two values being compared both have their corresponding bits set. The bits are compared using the following table

               1   &   1   ==   1
               1   &   0   ==   0
               0   &   1   ==   0
               0   &   0   ==   0

            An ideal use for this is to set up a mask to check the values of certain bits. Say we have a BYTE that contains some bit flags, and we want to check if bit four bit is set.

            BYTE b = 50;
            if ( b & 0x10 )
                cout << "Bit four is set" << endl;
            else
                cout << "Bit four is clear" << endl;

            This would result in the following calculation

                00110010  - b
             & 00010000  - & 0x10
              ----------
                00010000  - result

            So we see that bit four is set.

            The | operator

            The | (OR) operator compares two values, and returns a value that has its bits set if one or the other values, or both, have their corresponding bits set. The bits are compared using the following table

               1   |   1   ==   1
               1   |   0   ==   1
               0   |   1   ==   1
               0   |   0   ==   0

            An ideal use for this is to ensure that certain bits are set. Say we want to ensure that bit three of some value is set

            BYTE b = 50;
            BYTE c = b | 0x04;
            cout << "c = " << c << endl;

            This would result in the following calculation

                00110010  - b
              | 00000100  - | 0x04
              ----------
                00110110  - result

            The ^ operator

            The ^ (XOR) operator compares two values, and returns a value that has its bits set if one or the other value has its corresponding bits set, but not both. The bits are compared using the following table

               1   ^   1   ==   0
               1   ^   0   ==   1
               0   ^   1   ==   1
               0   ^   0   ==   0

            An ideal use for this is to toggle certain bits. Say we want toggle the bits three and four

            BYTE b = 50;
            cout << "b = " << b << endl;
            b = b ^ 0x18;
            cout << "b = " << b << endl;
            b = b ^ 0x18;
            cout << "b = " << b << endl;

            This would result in the following calculations

                00110010  - b
             ^ 00011000  - ^ 0x18
              ----------
                00101010  - result
            
                00101010  - b
            ^ 00011000 - ^ 0x18 ---------- 00110010 - result

            The ~ operator

            The ~ (Ones Complement or inversion) operator acts only on one value and it inverts it, turning all the ones int zeros, and all the zeros into ones. An ideal use of this would be to set certain bytes to zero, and ensuring all other bytes are set to one, regardless of the size of the data. Say we want to set all the bits to one except bits zero and one

            BYTE b = ~0x03;
            cout << "b = " << b << endl;
            WORD w = ~0x03;
            cout << "w = " << w << endl;

            This would result in the following calculations

                00000011  - 0x03
                11111100  - ~0x03  b
            
                0000000000000011  - 0x03
                1111111111111100  - ~0x03  w

            Another ideal use, is to combine it with the & operator to ensure that certain bits are set to zero. Say we want to clear bit four

            BYTE b = 50;
            cout << "b = " << b << endl;
            BYTE c = b & ~0x10;
            cout << "c = " << c << endl;

            This would result in the following calculations

                00110010  - b
             & 11101111  - ~0x10
              ----------
                00100010  - result

            The >> and << operators

            The >> (Right shift) and << (left shift) operators move the bits the number of bit positions specified. The >> operator shifts the bits from the high bit to the low bit. The << operator shifts the bits from the low bit to the high bit. One use for these operators is to align the bits for whatever reason (check out the MAKEWPARAM, HIWORD, and LOWORD macros)

            BYTE b = 12;
            cout << "b = " << b << endl;
            BYTE c = b << 2;
            cout << "c = " << c << endl;
            c = b >> 2;
            cout << "c = " << c << endl;

            This would result in the following calculations

                00001100  - b
                00110000  - b << 2
                00000011  - b >> 2

            Bit Fields

            Another interesting thing that can be done using bits is to have bit fields. With bit fields you can set up minature structures within a BYTE, WORD or DWORD. Say, for example, we want to keep track of dates, but we want to use the least amount of memory as possible. We could declare our structure this way

            struct date_struct {
                BYTE day   : 5,   // 1 to 31
                     month : 4,   // 1 to 12
                     year  : 14;  // 0 to 9999
                } date;

            In this example, the day field takes up the lowest 5 bits, month the next four, and year the next 14 bits. So we can store the date structure in twenty three bits, which is contained in three BYTEs. The twenty fourth bit is ignored. If I had declared it using an integer for each field, the structure would have taken up 12 BYTEs.

            |0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0|
               |                                   |          |           |
               +------ year -------------+ month + day --+

            Now lets pick this declaration apart to see what we are doing.

            First we will look at the data type we are using for the bit field structure. In this case we used a BYTE. A BYTE is 8 bits, and by using it, the compiler will allocate one BYTE for storage. If however, we use more than 8 bits in our structure, the compiler will allocate another BYTE, as many BYTEs as it takes to hold our structure. If we had used a WORD or DWORD, the compiler would have allocated a total of 32 bits to hold our structure.

            Now lets look at how the various fields are declared. First we have the variable (day, month, and year), followed by a colon that separates the variable from the number of bits that it contains. Each bit field is separated by a comma, and the list is ended with a semicolon.

            Now we get to the struct declaration. We put the bit fields into a struct like this so that we can use convention structure accessing notation to get at the structure members. Also, since we can not get the addresses of bit fields, we can now use the address of the structure.

            date.day = 12;
            
            dateptr = &date;
            dateptr->year = 1852;


            posted @ 2005-11-21 08:03 味全每日C++ 閱讀(753) | 評論 (0)編輯 收藏

            2005年11月14日 #

                今天參加MS2006年度秋季校園招聘會的筆試第三場,有一個算法題,求一個樹種兩個節點的最低公共節點,在網上Google了一下,看到原題大致這樣的:
                  Given the values of two nodes in a *binary search tree*, write a c program to find the lowest common ancestor. You may assume that both values already exist in the tree.

            The function prototype is as follows: int FindLowestCommonAncestor(node* root,int value1,int value)
                       20
                      /  \
                     8    22
                   /   \
                  4     12
                       /  \
                     10    14
                構筑函數: struct TreeNode * FindLowestCommonTreeNode(struct node *pNode,)

            Struct TreeNode
            {
               int Data;
               TreeNode *pLeft, *pRight;
            }

            FindLowestAncestor(Struct TreeNode *pRoot, Struct TreeNode *pNode1, Struct TreeNode *pNode2)
            {
               if (pRoot==NULL) 
                  return NULL;
               if (pRoot==pNode1 && pRoot==pNode2) 
                  return pRoot;
               Struct TreeNode *pTemp;
               if (pTemp = FindLowestAncestor(pRoot->pLeft,pNode1,pNode2)) 
                  return pTemp;
               if (pTemp = FindLowestAncestor(pRoot->pRight,pNode1,pNode2)) 
                  return pTemp;
               if (FindLowestAncestor(pRoot,pNode1,pNode1) && FindLowestAncestor(pRoot,pNo
            de2,pNode2)) return pRoot;

               return NULL;
            }

            posted @ 2005-11-14 02:05 味全每日C++ 閱讀(1325) | 評論 (5)編輯 收藏

            2005年11月2日 #

             

            char ** p1;                                   //    pointer to pointer to char
            const char **p2;                           //    pointer to pointer to const char
            char * const * p3;                         //    pointer to const pointer to char
            const char * const * p4;                //    pointer to const pointer to const char
            char ** const p5;                          //    const pointer to pointer to char
            const char ** const p6;                 //    const pointer to pointer to const char
            char * const * const p7;                //    const pointer to const pointer to char
            const char * const * const p8;       //    const pointer to const pointer to const char


            注:p1是指向char類型的指針的指針;
                    p2是指向const char類型的指針的指針;
                    p3是指向char類型的const指針;
                    p4是指向const char類型的const指針;
                    p5是指向char類型的指針的const指針;
                    p6是指向const char類型的指針的const指針;
                    p7是指向char類型const指針的const指針;
                    p8是指向const char類型的const指針的const指針。

            typedef char * a;       // a is a pointer to a char 

            typedef a b();            
            // b is a function that returns a pointer to a char

            typedef b 
            *c;            // c is a pointer to a function that returns a pointer to a char 

            typedef c d();           
            // d is a function returning a pointer to a function that returns a pointer to a char 

            typedef d 
            *e;           // e is a pointer to a function returning a pointer to a function that a pointer to a char 

            e var[
            10];               // var is an array of 10 pointers to functions returning pointers to  functions returning pointers to chars.


            原文地址:http://www.codeproject.com/cpp/complex_declarations.asp

            posted @ 2005-11-02 22:08 味全每日C++ 閱讀(2371) | 評論 (9)編輯 收藏

            2005年10月27日 #

            Yin Feilong

            Address: Room 110 Building 11 Nanjing University Hankou Road 22, Nanjing, Jiangsu Province 210093

            Phone: (86-25) 8359-4465  +86135-8519-7909

                   E-mail: yinfeil@gmail.com             Homepage: http://www.seman.cn

            Objective:

            C++ Software Design Engineer

            Education:

                  B.E Department of Information Management, Nanjing University.  Aug.2002 – Present

                  GPA: Overall: 3.2/4.0

            Academic Main Courses:

            Development Tools of Management Information System

            Management Information Systems and software Engineering

            Information Analysis and Policy Making, Information Retrieval and Storage

            Programming Languages (C), Data Structures, Database Systems

            Computer Network, System Science and Techniques, Information Organization

            Computer Abilities:

                  Certification:

                       National Computer Rank Examination Grade Three(NCRE-3)

                  Qualification of Computer and Software Technology Proficiency: Software Designer

                  Skills:

            Expert: C/C++, Visual Foxpro, HTML, Asp, CSS

            Intermediate: Rational Rose, SQL Server, XML, Java, Project 2003

            Beginner: C#, Asp.net, Visual C++, Oracle

            English Skills:

            Have a good command of both spoken and written English. Past CET-4

            Experiences:

                  Developer. Lily-Studio of Nanjing University, June 2003 – May 2004

                       Designed and implemented the Community of Lily Alumni

                          Editor in chief of the magazine Network Guide

                   Lab Manager. Information Technology Lab. June 2004 – Present

            Supervisor of Network Application, Designed and implemented FTP、SMTP-based mail ServerVPN Web Server

            Designed and implemented 2 websites of Department of Information Management and School of Public, using ASP and ACCESS

                          Designed and implemented the platform of Tech-Learn Information

                       Translate some parts of Web-based Analysis for competitive.

            Honors:   

                   Football、Ping pong

            posted @ 2005-10-27 16:36 味全每日C++ 閱讀(1689) | 評論 (1)編輯 收藏

            2005年10月24日 #

                 摘要:   #include "iostream.h"#include "stdlib.h"#include "stack.h"#pragma oncetemplate<class T>class CBiTree{    public:    ...  閱讀全文
            posted @ 2005-10-24 11:06 味全每日C++ 閱讀(1483) | 評論 (1)編輯 收藏

            僅列出標題  
            国产亚洲美女精品久久久| 亚洲中文字幕无码久久精品1| 精品多毛少妇人妻AV免费久久 | 91麻豆精品国产91久久久久久| 亚洲国产欧洲综合997久久| 要久久爱在线免费观看| 久久久久国产| 怡红院日本一道日本久久| 久久久一本精品99久久精品66 | 久久强奷乱码老熟女网站| AAA级久久久精品无码区| 亚洲午夜久久影院| 狠狠精品干练久久久无码中文字幕| 久久99毛片免费观看不卡| 久久亚洲综合色一区二区三区| 色综合久久中文综合网| 久久99精品免费一区二区| 久久人妻少妇嫩草AV蜜桃| 一级做a爰片久久毛片毛片| 亚洲欧洲精品成人久久曰影片| 中文字幕乱码久久午夜| 青青草原精品99久久精品66| 久久久久亚洲AV无码网站| av午夜福利一片免费看久久 | 精品水蜜桃久久久久久久| 久久国产精品免费一区| 久久久久久久久久久| 99久久成人国产精品免费| 久久国产精品无码网站| 无码伊人66久久大杳蕉网站谷歌| 国产精品久久久久9999高清| 久久久久18| 久久精品毛片免费观看| 久久久久久A亚洲欧洲AV冫| 久久人人爽人人爽人人AV| 97超级碰碰碰碰久久久久| 狠狠色婷婷久久综合频道日韩| 国内精品久久久久久99蜜桃 | 四虎影视久久久免费| 久久精品亚洲日本波多野结衣| 久久精品二区|