• <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>
            posts - 16,  comments - 34,  trackbacks - 0

            編譯C/C++源代碼時,源代碼首先會被預處理器(preprocessor)進行預處理(preprocess)。
            預處理器執行源代碼中的預處理指令,如:
            ——文件包含
            #include
            ——條件編譯
            #if、 #ifdef、 #ifndef、 #elif、 #else、 #endif
            ——宏
            #define、 #undef、宏標識符、宏擴展
            ——其他
            #error、#line、#pragma
            ……

            預處理之后的結果(即將提交給編譯器)與程序員看到的源代碼也許會有很大的差異。
            尤其在源代碼中含有許多錯綜復雜的宏與條件編譯時。
            當我們被這些狂亂的宏與條件編譯折磨的時候, 如果能看到預處理的結果, 也許會有很大的幫助。

            下面將以一個示例說明msvc與gcc中得到預處理結果的方式。



            零、 示例

            假設我們需要查看 _MSC_VER 與 __GUNC__ 兩個宏最終被擴展出的文本: 
            int main() {
                
            int result = 
            #if defined(__GNUC__)
            __GNUC__
            #elif defined(_MSC_VER)
            _MSC_VER
            #else
            #error unknown compiler
            #endif
            ;
                
            return result;
            }

            該程序很簡單, main函數返回一個result,然后立即退出。
            而result的值, 根據條件編譯得到:
            1. 如果是GCC編譯器, 那么result賦值為__GNUC__
            2. 否則如果是VC編譯器, 那么result賦值為_MSC_VER
            3. 否則是一個未知的編譯器, 錯誤

            接下來, 我們來看看_MSC_VER與__GNUC__這2個宏最終到底被擴展為什么文本。




            一、 GCC

                    一.1、 -E 選項

            -E選項將把預處理的結果,寫入stdout。
            也就是說, 執行如下命令:
            gcc -E preporcess_only.c

            就能在控制臺中得到預處理后的結果,大致如下:
            # 1 "../preprocess_only.c"
            # 1 "<built-in>"
            # 1 "<command line>"
            # 1 "../preprocess_only.c"
            int main() {
                int result =

            3





            ;
                return result;
            }


            可以看到, __GUNC__ 宏最終被擴展為整數字面量3(GCC 3)。

            如果源代碼很長, 輸出到命令行窗口中查看也許不方便。
            如何將其輸出到一個文件中呢?


                            一.1.1、 重定向

            因為-E是輸出到stdout, 顯然可以將其重定向到另一個文件, 如執行如下命令:
            gcc -E preprocess_only.c >stdout.txt

            那么stdout.txt中, 就能得到剛才命令行窗口中的內容。


                            一.1.2、 -o (小寫) 選項

            -o選項用于指定出文件名。
            對于-c, -o指定的是目標文件名。
            對于-S ,-o指定的是匯編文件名。
            對于-E, -o自然也可以指定預處理文件名, 如執行如下命令:
            gcc -E preprocess_only.c -o output.txt

            那么output.txt中會得到“一.1.1”中的stdout.txt和“一.1”中控制臺窗口一樣的結果。


                    一.2、-save-temps 選項

            -save-temps選項將保留中間文件:如預處理后的結果文件、匯編代碼文件與目標文件。
            其中的預處理結果文件(通常有.i后綴)是我們所需要的。


            舉例:
            1、 gcc -save-temps -E preprocess_only.c
            0個中間文件。
            輸出預處理結果, 同“一.1”一樣, 輸出到控制臺窗口中。
            對比如下命令:

            1.1、 gcc -save-temps -E preprocess_only.c -o temp_output.txt
            1.2、 gcc -save-temps -E preprocess_only.c >temp_output.txt
            可以看出, -E選項不產生中間文件。 預處理結果就是最終結果。
            同時可以使用 -o選項或者重定向, 把結果保存到一個文件中。


            2、 gcc -save-temps -S preprocess_only.c
            1個中間文件: preprocess_only.i(預處理結果)
            1個輸出文件:preprocess_only.s(匯編代碼)
            對比如下命令:

            2.1、 gcc -save-temps -S preprocess_only.c -o unknown
            得到preprocess_only.i文件,內容是預處理結果,是中間文件。
            得到unknown文件,內容是匯編代碼, 是最終結果文件。


            3、 gcc -save-temps -c preprocess_only.c
            2個中間文件: preprocess_only.i與preprocess_only.s。
            1個輸出文件: preprocess_only.o(目標代碼)
            對比如下命令:

            3.1、 gcc -save-temps -c preprocess_only.c -o unknown
            得到preprocess_only.i 與 preprocess_only.s文件,內容分別是預處理結果與匯編代碼,是中間結果。
            unknown文件, 內容是目標代碼,是最終結果文件。

            4、 gcc -save-temps preprocess_only.c
            3個中間文件: preprocess_only.i、preprocess_only.s、preprocess_only.o。
            1個輸出文件: a.out(a.exe with mingw)。
            對比如下命令:

            4.1、 gcc -save-temps preprocess_only.c -o what
            得到上述3個文件, 是中間文件。
            what文件(what.exe with mingw), 內容是可執行代碼, 是最終結果文件。





            二、 MSVC

            VC6、8、9中與查看預處理相關的選項可以通過如下命令查看:
            cl /help

            在輸出中, 找 -PREPROCESSOR- 這個類別。
            其中與預處理結果相關的有如下一些選項:

                    二.1、/E 選項

            /E preprocess to stdout
            /E 將預處理定向到 stdout

            顯然, 這和“一.1”是等價的, 如:
            cl /E preprocess_only.c

            在命令行窗口中將得到類似結果
            #line 1 "preprocess_only.c"
            int main() {
                int result = 


            #line 6 "preprocess_only.c"
            1200


            #line 10 "preprocess_only.c"
            ;
                return result;
            }

            可以看到, _MSC_VER宏最終被擴展為整數字面值1200(VC6)。

            對于較長的源文件, 我們同樣希望將結果輸出到一個文件中。


                            二.1.1、重定向

            執行:
            cl /E preprocess_only.c >stdout.txt

            stdout.txt將保存上面的結果。

            注意: 在msvc中,沒有“一.1.2”的對應物。
            執行:
            cl /help

            在輸出中找到-OUTPUT FILES-類別, 可以看到沒有命名預處理結果的方式。有兩個相似的選項:
            /Fe 命名可執行文件。
            /Fp 命名預編譯頭文件。
            但不是我們需要的選項。


            也許VC認為通過 “/E + 重定向”就可以達到命名輸出文件的目的。
            所以就沒有設計達到此目的的另一種方法。


                    二.2、/P 選項

            /P preprocess to file
            /P 預處理到文件

            執行:
            cl /P preprocess_only.c

            將得到 preprocess_only.i

            /P會將對 xxx.suffix 的預處理結果輸出到 xxx.i 文件中。
            沒有指定文件名的方式。 如果需要指定輸出文件名, 可以使用 “/E + 重定向”


                    二.3 /EP 選項

            /E與/P選項都將保留一部分(源文件)行信息,如“二.1”所示。
            如果這是不需要的, 可以使用 /EP選項。

            /EP preprocess to stdout, no #line
            /EP 預處理到標準輸出,沒有 #line

            如:
            cl /EP preprocess_only.c

            將得到如下輸出:

            int main() {
                
            int result = 



            1200



            ;
                
            return result;
            }


            同樣, 如果需要輸出到指定文件, 可以使用重定向。


                    二.4 其他一些有趣的選項

            1. /C (大寫)
            don't strip comments(不抽出注釋)
            如果保留注釋對理解預處理結果有幫助, 可以使用這個選項。

            2. /U /u
            /u remove all predefined macros
            /u 移除所有預定義的宏

            /U<name> remove predefined macro
            /U<name> 移除預定義的宏

            比如可以通過:
            cl /u preprocess_only.c
            cl /U_MSC_VER preprocess_only.c

            來得到一個 unknown complier錯誤囧……


            3. /D
            /D<name>{=|#}<text> define macro
            /D<name>{=|#}<text> 定義宏

            可以通過:
            cl /D__GUNC__=3 preprocess_only.c

            來假裝gcc編譯器囧……



             


            相關鏈接:

            ——示例文件下載
            http://immature.googlecode.com/svn/trunk/iMmature/sample/compiler_options/preprocess_only/
            http://www.shnenglu.com/Files/ownwaterloo/preprocess_only.zip

            ——《配置msvc命令行環境》
            http://www.shnenglu.com/ownwaterloo/archive/2009/04/15/environment_for_using_cl_from_command_line.html

            ——《配置msvc命令行環境(續)——編寫msvc編譯腳本》
            http://www.shnenglu.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html

            ——《預定義_MSC_VER宏》
            http://www.shnenglu.com/ownwaterloo/archive/2009/04/15/predefined_macro__MSC_VER.html

            ——《預定義__GNUC__宏》
            http://www.shnenglu.com/ownwaterloo/archive/2009/04/16/predefined_macro___GNUC__.html
             


             

             
            Creative Commons License
            作品采用知識共享署名-非商業性使用-相同方式共享 2.5 中國大陸許可協議進行許可。

            轉載請注明 :
            文章作者 - OwnWaterloo
            發表時間 - 2009年04月16日
            原文鏈接 - http://www.shnenglu.com/ownwaterloo/archive/2009/04/16/preprocess_only.html

            posted on 2009-04-16 00:49 OwnWaterloo 閱讀(13273) 評論(4)  編輯 收藏 引用

            FeedBack:
            # re: 查看源文件預處理結果
            2009-04-21 09:20 | hede
            問題是怎么能只除掉部分預處理特別是#ifdef這樣的  回復  更多評論
              
            # re: 查看源文件預處理結果
            2009-04-21 14:45 | OwnWaterloo
            將需要處理掉的那部分單獨copy出來可以嗎?  回復  更多評論
              
            # re: 查看源文件預處理結果
            2009-06-08 11:25 | zhichyu
            請教博主一個問題:gcc -E輸出看不大明白,其中的"# 1"等是什么含義?我看了gcc和cpp的聯機幫助還是不明白。博主是否了解相關信息?  回復  更多評論
              
            # re: 查看源文件預處理結果
            2009-06-08 15:27 | OwnWaterloo
            @zhichyu
            應該跟源文件行號有關, 具體我不清楚  回復  更多評論
              
            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            常用鏈接

            留言簿(8)

            隨筆檔案(16)

            鏈接

            搜索

            •  

            積分與排名

            • 積分 - 197903
            • 排名 - 133

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

            avtt天堂网久久精品| 精品国产热久久久福利| 曰曰摸天天摸人人看久久久| 欧美国产成人久久精品| 国产精品久久久天天影视| 久久人妻无码中文字幕| 国产亚洲美女精品久久久| 国内精品人妻无码久久久影院| 人妻无码久久精品| 中文字幕一区二区三区久久网站| 久久国语露脸国产精品电影| 久久久久国产日韩精品网站| 久久精品视频免费| 久久精品中文騷妇女内射| 久久精品国产99国产精品亚洲| 色诱久久av| 久久久久久极精品久久久| 国产福利电影一区二区三区久久老子无码午夜伦不 | 久久久无码精品亚洲日韩蜜臀浪潮| 人妻丰满?V无码久久不卡| 久久久精品久久久久特色影视| 99久久精品国产一区二区蜜芽| 国产99精品久久| 99国产欧美久久久精品蜜芽| 亚洲精品国精品久久99热一| 2021国产精品久久精品| 青春久久| 伊人久久大香线蕉成人| 色婷婷久久久SWAG精品| 欧美精品丝袜久久久中文字幕 | 大香伊人久久精品一区二区| 亚洲精品国产第一综合99久久| 久久综合成人网| 亚洲精品97久久中文字幕无码| 免费一级做a爰片久久毛片潮| 亚洲精品成人网久久久久久| 一本久久综合亚洲鲁鲁五月天| 伊人色综合九久久天天蜜桃| 久久人做人爽一区二区三区| 亚洲欧美日韩久久精品第一区| 久久久久国产精品熟女影院|