當前位置:首頁 » 編程軟體 » 看雪vs編譯器優化

看雪vs編譯器優化

發布時間: 2023-02-04 14:56:58

A. VC編譯器中「優選大小或速度」和「優化」選項的設置區別在哪裡

VC中的優化裡面的 按大小優化 與 按速度優化 是分開選的,不能同時選擇兩者

B. Debug模式下怎樣去掉編譯器的優化解決思路

通常開發的程序有2種模式:Debug模式和Release模式。
在Debug模式下,編譯器會記錄很多調試信息,也可以加入很多測試代碼,方便程序員測試,以及出現bug時的分析解決。
Release模式下,就沒有上述那些調試信息,而且編譯器也會自動優化一些代碼,這樣生成的程序性能是最優的,但是如果出現問題,就不方便分析測試了。

C. c語言防止優化

編譯器編譯命令里有設置選項,通過設置,你可以要求 不優化,也可以要求用哪種優化。
具體選項有哪些,要查自己編譯器的幫助文件。
例如,MS VC++ 6.0 編譯器編
優化選項:
/O1:優化使產生的可執行代碼最小
/O2:優化使產生的可執行代碼速度最快
/Oa:指示編譯器程序里沒有使用別名,可以提高程序的執行速度
/Ob:控制內聯(inline)函數的展開
/Od:禁止代碼優化
/Og:使用全局優化
/Oi:用內部函數去代替程序里的函數調用,可以使程序運行的更快,但程序的長度變長
/Op:提高浮點數比較運算的一致性
/Os:產生盡可能小的可執行代碼
/Ot:產生盡可能塊的可執行代碼
/Ow:指示編譯器在函數體內部沒有使用別名
/Ox:組合了幾個優化開關,達到盡可能多的優化
/Oy:阻止調用堆棧里創建幀指針

/O2 為了加速,會優化掉。 選 /Od 不優化。

D. java編譯器的代碼優化問題

理論上的就不說了,你自己搜也能搜到很多。
舉個例子,你從一個方法a調用了另一個方法b。
我們知道,在a和b之中是可以創建相同名稱的變數的,比如都有int i = 0;這句話。這種現象的根本原因在於,方法的調用會產生中斷,中斷產生後,cpu會做現場保護,包括把變數等進行壓棧操作,即把方法a的相關資源進行了壓棧,而方法b的相關資源放在棧頂,只有棧頂資源可以與cpu交互(就把方法a中的變數i保護起來),當方法b結束後出棧,a就又回到了棧頂,並獲取了方法b運行的結果,然後繼續運行。

哎,有些啰嗦了。方法的調用、中斷、壓棧出棧等等這些操作你說一點不消耗資源吧,那是不可能的,多少都會消耗一些,雖然很非常十分微不足道。那麼編譯器的優化過程,我知道的其作用之一,就是會把這些做一個優化。原本方法a一共10句話,你偏要只寫1句,然後第2句寫成方法b,第3句寫成方法c。。。。。,然後依次嵌套調用。這樣的源代碼,編譯器優化後,就跟你直接寫10句是一個結果,即做了一定程度上的優化。

E. 如何防止因編譯器開啟優化,而導致程序執行錯誤

我的經驗是:未優化的c程序可正常運行,優化後不能運行,那一定是我的程序有問題。我還沒經歷過不是我程序的情況。
發現這種不易發現的問題,需要看匯編碼。
避免的方法,我的經驗:寫c程序,盡量規矩;似是而非的概念,一定要搞清楚,別僥幸。因為僥幸而留的雷,現在不出問題,將來一定會出問題;不優化不出問題,優化就出問題。
最後要說,每個應用程序,都讓他開優化運行,只要時間允許,一定要查出開優化後出問題的原因。時間不允許,只能不開優化湊合著,在有時間的時候繼續查問題。

F. 編譯器的任務是什麼 尾遞歸優化

當編譯器檢測到一個函數調用是尾遞歸的時候,它就覆蓋當前的活動記錄而不是在棧中去創建一個新的。編譯器可以做到這點,因為遞歸調用是當前活躍期內最後一條待執行的語句,於是當這個調用返回時棧幀中並沒有其他事情可做,因此也就沒有保存棧幀的必要了。通過覆蓋當前的棧幀而不是在其之上重新添加一個,這樣所使用的棧空間就大大縮減了,這使得實際的運行效率會變得更高。雖然編譯器能夠優化尾遞歸造成的棧溢出問題,但是在編程中,我們還是應該盡量避免尾遞歸的出現,因為所有的尾遞歸都是可以用簡單的goto循環替代的。

G. 用什麼軟體來查看一個用Microsoft Visual C++ 6.0 編寫的程序的源代碼

標 題: MFC逆向初級研究(1)
作 者: 北斗之搖光
時 間: 2007-03-15 17:14
鏈 接: http://bbs.pediy.com/showthread.php?t=41087
詳細信息:

【文章標題】: MFC逆向初級研究(1)
【文章作者】: 北斗之搖光
【作者郵箱】: [email protected]
【下載地址】: 自己搜索下載
【作者聲明】: 只是感興趣,沒有其他目的。失誤之處敬請諸位大俠賜教!
--------------------------------------------------------------------------------
【詳細過程】
引言
本文主要針對微軟的VC++6.0中使用MFC產生的EXE文件的逆向研究,我曾經使用微軟的Visual Studio 2005編譯了一
個EXE文件,通過IDA反匯編以後發現該文件與VC++6.0產生的文件還是有所區別,因此特別在此聲明一下。文中主要使用了I
DA pro 5.0和在看雪(www.pediy.com)下載的OllyICE作為工具對目標文件進行反匯編。在此也感謝看雪論壇的各位的無私奉
獻,在研究過程的中的困難多通過各位的帖子得到了幫助。
逆向的關鍵
我認為逆向的關鍵主要是要弄明白目標文件的演算法和實現過程,在Window操作系統下,軟體的實現過程就體現在其
對Window消息的處理,而軟體的演算法則包含在處理的具體過程中。對於通過SDK編寫的"傳統"的Windows應用程序基本都具備
幾個共同的特徵:WinMain函數、WinProc函數、窗口注冊、消息循環。對於這類目標文件的分析主要集中的WinProc的分析上
,WinProc的函數地址獲得一般是通過窗口注冊函數中的參數獲得。(由於我對於這類文件沒有具體逆向過,所以只是大概的
說說,有不對的地方請各位不要客氣,盡管拍磚)
而使用MFC(Microsoft Function Class)顧名思義,該類庫主要封裝了大部分的Windows API函數所以在代碼中看
不到原本的SDK編程中的消息循環、窗口過程函數等等東西,所有這些封裝在相應的mfcxx.dll中,讓程序員能夠專著與處理
過程與演算法。這種做法於逆向而言有好處也有壞處:
壞處就是加大了對於MFC產生的EXE文件的逆向難度,讓許多的和我一樣的菜鳥迷失在匯編代碼中找不找北了,基本主要就靠
猜測實現過程中用到了那些函數,然後對文件導入表的函數下斷點來尋找我們所需要的處理過程;
好處就是這樣的做法使得EXE文件中主要都是目標程序的Window消息處理流程以及演算法,而且dll中的大部分函數的功能都能
在MSDN中查到。如果能夠通過對目標文件的分析得到這個Window消息處理流程和演算法架構,基本上我們就可以重寫整個軟體;
要做到上面的目標,首先我們要對MFC有所了解,推薦沒有基礎的兄弟們讀讀候俊傑的《深入淺出MFC》。該書在逆向過
程中完全可以作為一本參考書,讓你能通過源代碼了解實現過程,網上有很多該書的電子版下載。
一個逆向MFC產生的EXE文件的例子
下面我們就通過一個具體的例子來學習一下如何從目標文件中挖到我們需要的東西。首先我們來產生一個需要的EXE文件。
在此我假定各位對MFC有過一定的使用經驗,畢竟逆向分析才是本文的重點。
1.產生例子所需要的目標文件:
我們通過VC++6.0的向導來產生一個名為ReverseMFC的工程,這個工程的設置情況如下:
Application type of fff:
Dialog-Based Application targeting:
Win32
Classes to be created:
Application: CFffApp in ReverseMFC.h and ReverseMFC.cpp
Dialog: CFffDlg in ReverseMFCDlg.h and ReverseMFCDlg.cpp
Features:
+ Uses shared DLL implementation (MFC42.DLL)
+ Localizable text in:
中文[中國]
直接編譯以後就能夠運行,為了確定我們是否正確的分析的整個目標文件,在該對話框中加入一個我們自定義的按鈕如
下,對於該按鈕的處理函數如下設定為:
AfxMessageBox("I find it!",MB_OK);編譯後就得到了我們需要的目標文件。
現在我們得到了所需要的目標文件,在IDA中載入該文件。在此我們最好是產生Release版本的EXE文件,畢竟所有的發
布軟體都是Release版本的。
2.具體分析
在IDA中按Ctrl+S找到.rdata段,該段主要存儲了目標文件的類運行時創建信息、MessageMap信息、MessageEntry信息、
虛函數表、RTTI數據(如果編譯選項中選擇了支持RTTI的話)。
在到達.rdata段後我們可以看到這樣的代碼,對數據進行格式轉換後可以得到如下圖所示的數據。
.rdata:004021C0 ; 屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯?
.rdata:004021C0
.rdata:004021C0 ; Segment type: Pure data
.rdata:004021C0 ; Segment permissions: Read
.rdata:004021C0 _rdata segment para public 'DATA' use32
.rdata:004021C0 assume cs:_rdata
.rdata:004021C0 ;org 4021C0h
.rdata:004021C0 off_4021C0 dd offset sub_401000 ; DATA XREF: sub_401010o
.rdata:004021C4 dd offset dword_4021C8
.rdata:004021C8 dword_4021C8 dd 111h ; DATA XREF: .rdata:004021C4o
.rdata:004021CC dd 0
.rdata:004021D0 dd 0E146h
.rdata:004021D4 dd 0E146h
.rdata:004021D8 dd 0Ch
.rdata:004021DC dd offset CWinApp::OnHelp(void)
.rdata:004021E0 dd 0
.rdata:004021E4 dd 0
.rdata:004021E8 dd 0
.rdata:004021EC dd 0
.rdata:004021F0 dd 0
.rdata:004021F4 dd 0
.rdata:004021F8 off_4021F8 dd offset CWinApp::GetRuntimeClass(void)
.rdata:004021F8 ; DATA XREF: unknown_libname_1-56o
.rdata:004021FC dd offset sub_401040
.rdata:00402200 dd offset nullsub_2
.rdata:00402204 dd offset nullsub_3
.rdata:00402208 dd offset nullsub_2
.rdata:0040220C dd offset CCmdTarget::OnCmdMsg(uint,int,void *,AFX_CMDHANDLERINFO *)
其中的off_4021C0就是一個MessageMap數據;dword_4021C8就是MessageMap所指的MessageEntry數據;off_4021F8就是一個
類的虛函數表的開始位置。那麼具體這些數據時那個類的相關數據呢?如此判斷的依據是什麼?
首先我們知道MessageEntry是的數據結構定義如下,而且以6個0表示整個數組的結束。
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // windows message
UINT nCode; // control code or WM_NOTIFY code
UINT nID; // control ID (or 0 for windows messages)
UINT nLastID; // used for entries specifying a range of control id's
UINT nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
因此我們有理由假設"dword_4021C8就是MessageMap所指的MessageEntry數據"。
而MessageMap數據結構定義如下:
struct AFX_MSGMAP
{
#ifdef _AFXDLL
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
#else
const AFX_MSGMAP* pBaseMap;
#endif
const AFX_MSGMAP_ENTRY* lpEntries;
};
off_4021C0的兩個數據中第二個數據恰恰就是我們前面假設為MessageEntry的指針,跟入其第一個數據,我們看到如下的代
碼:
.text:00401000 ; *************** S U B R O U T I N E ***************************************
.text:00401000
.text:00401000
.text:00401000 sub_401000 proc near ; DATA XREF: .rdata:off_4021C0o
.text:00401000 mov eax, ds:AFX_MSGMAP const CWinApp::messageMap
.text:00401005 retn
.text:00401005
.text:00401005 sub_401000 endp
恰恰是一個返回基類的MessageMap的函數。因此我們也同樣有理由假設"off_4021C0就是一個MessageMap數據"。
對於虛函數表的假設是如何被證明呢?首先我們要知道關於虛函數表的一點知識:虛函數表由虛函數的地址組成,表中函數
地址的順序和它們第一次出現的順序(即在類定義的順序)一致。若有重載的函數,則替換掉基類函數的地址。通過這個我
們可以知道MFC中虛函數表中的函數順序必然是先按照CObject->CCmdtarget->。。。。這個類繼承順序中的虛函數順序來處
理虛函數表中的函數順序的。只要證明這個我們"假設的虛函數"中的函數順序與上面提到的知識相符合則有理由說明我們的
假設成立。
首先來看CObject中虛函數的順序,在查看CObject的聲明文件後得到了這個類的虛函數順序:
virtual CRuntimeClass* GetRuntimeClass() const;
virtual ~CObject(); // virtual destructors are necessary
virtual void Serialize(CArchive& ar);
#if defined(_DEBUG) || defined(_AFXDLL)
// Diagnostic Support
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
再來查看CCmdtarget的虛函數順序,在查看CObject的聲明文件後得到了這個類的虛函數順序:
DECLARE_DYNAMIC(CCmdTarget);
virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo);
#ifndef _AFX_NO_OLE_SUPPORT
// called when last OLE reference is released
virtual void OnFinalRelease();
#endif
#ifndef _AFX_NO_OLE_SUPPORT
// called before dispatching to an automation handler function
virtual BOOL IsInvokeAllowed(DISPID dispid);
virtual BOOL GetDispatchIID(IID* pIID);
virtual UINT GetTypeInfoCount();
virtual CTypeLibCache* GetTypeLibCache();
virtual HRESULT GetTypeLib(LCID lcid, LPTYPELIB* ppTypeLib);
之所以還要列出"DECLARE_DYNAMIC(CCmdTarget);"是因為這個宏的定義如下:
#define DECLARE_DYNAMIC(class_name) \
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static const AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
這個virtual CRuntimeClass* GetRuntimeClass() const; 覆蓋掉了一開始的CObject的相對應函數。依次按照類的順序對
照下來,就可以知道該表確實是虛函數表。同時,對應的GetMessageMap虛函數的位置上跟入後,可以得到如下代碼:
.text:00401010 ; *************** S U B R O U T I N E ***************************************
.text:00401010
.text:00401010
.text:00401010 sub_401010 proc near ; DATA XREF: .rdata:00402228o
.text:00401010 mov eax, offset off_4021C0
.text:00401015 retn
.text:00401015
.text:00401015 sub_401010 endp

恰恰是返回了我們之前假設的MessageMap的地址。

--------------------------------------------------------------------------------
【版權聲明】: 本文原創於看雪技術論壇, 轉載請註明作者並保持文章的完整, 謝謝!

H. 阿里C++筆試題:const int a = 10;int * p = (int *)(&a);*p=20; 為什麼結果是a=10,*p=20

編譯器優化的結果,編譯器在處理 const int a = 10;
這句時 沒有為a分配內存賦值,而是在加入了符號表,後續引用a時有些類似#define a 10這樣處理了
int * p = (int *)(&a);這句則 配*p被強制賦值,所以指針有效指向了某個地址,所以出現了上述結果

熱點內容
英雄聯盟技能腳本 發布:2024-05-17 14:59:41 瀏覽:444
全名k歌安卓手機裡面怎麼錄屏 發布:2024-05-17 14:40:07 瀏覽:180
常用資料庫介紹 發布:2024-05-17 14:31:38 瀏覽:504
中孚存儲介質信息消除工具 發布:2024-05-17 14:31:33 瀏覽:589
伺服器訪問ip如何調轉主頁 發布:2024-05-17 14:30:33 瀏覽:789
好玩的解壓化妝小游戲 發布:2024-05-17 14:10:57 瀏覽:127
交通銀行怎麼登陸不了密碼 發布:2024-05-17 13:54:48 瀏覽:543
安卓如何自動連接無線 發布:2024-05-17 13:53:51 瀏覽:262
python的urlparse 發布:2024-05-17 13:44:20 瀏覽:769
linux命令全稱 發布:2024-05-17 12:07:54 瀏覽:110