vc6 產生最小的exe檔案

來源:互聯網
上載者:User

編譯出體積儘可能的小的exe,步驟如下:
1.扔掉CRT.
CRT提供了大量常用的函數.可說只要C/C++程式基本都會用到它.但是獲得了方便的同
時也增大了不少體積.雖然可以通過動態連結到外部的dll來解決,但是自此就有了對一
個更大的dll的依賴.所以要減肥,就要先拿CRT開刀.
在cl的編譯參數中加上/MD,再在link中加上/nodefaultlib:msvcrt.lib即可避免連結
到crt(靜態crt的lib檔案名稱我不清楚,所以就先連結成動態,再去除對應的msvcrt.lib)

2.重載new,new[],delete,delete[]
C/C++程式少不了動態分配記憶體,前面丟掉了CRT,再編譯器會發現反是有記憶體配置的地方都
在報錯,這是因為我去掉了crt,編譯器找不到對應的函數所致.所以要自己寫記憶體配置函數.
C的malloc和C++的new/new[]都是在當前的堆上分配記憶體.所以只要照著寫一遍就可以了:

C/C++ code
typedef UINT size_t; 
void*malloc(size_t size)
{
return HeapAlloc (GetProcessHeap(),NULL,size);
}
void free (void*memblock)
{
HeapFree (GetProcessHeap(),NULL,memblock);
}
void*realloc(void*memblock,size_t size)
{
return HeapReAlloc (GetProcessHeap(),NULL,memblock,size);
}
void*operatornew(size_t count)
{
return malloc (count);
}
void*operatornew[](size_t count)
{
return malloc (count);
}
voidoperator delete(void* _Ptr) throw( )
{
free (_Ptr);
}
voidoperator delete[](void* _Ptr) throw( )
{
free (_Ptr);
}

3.常用函數的替代.
沒了CRT許多常用的函數都無法使用,全部自己重寫無疑大大加大了程式的代
碼量,也沒多大意義.windows提供了很多常用的函數.都由系統的dll來提供,
使用它們就不用
a 字串處理函數.
  字串處理函數的替代品很多,kernel32.dll提供了lstr***的函數.完全
可以滿足字串處理的需要,C的格式化字串sprintf函數很好用,而user32.dll
也提供了相應的函數wsprintf/wvsprintf用於替代.沒有字串尋找函數有點麻煩
不過自己寫也要不了幾行代碼,或者乾脆用Shlwapi.dll提供的更完整的字串處理
庫來替代.
b 命令列輸入/輸出函數.
  這個...系統還真沒提供啥對應的函數,不過好在常用也不是太複雜.用Console API寫
幾條常用的getline和puts就足夠了.

4.重新指定進入點.
  如果問VC程式的進入點是什麼,估計會有不少人回答是main/WinMain.
沒錯.這是使用了標準的CRT的程式的進入點.但是實際的入口函數是CRT內部編寫好的.在
完成庫的初始化後再調用main/WinMain.既然移除了CRT,連結器自然就會發出找不到入口
函數的錯誤,解決方案很簡單,用/entry:指定一個函數就可以了.我仍然用習慣的main.
但是注意,這個main不能帶任何的參數.帶了也用不了.

5.更改節的對齊大小.
cl編譯器預設的對齊大小是4K(4096)這個數值的設定是個問題.有時候會使編譯出來的程式無
法執行.這個只有自己反覆的實驗了.我將它設定為512(其實還可以更小,但是小於512的程式不能使用upx壓縮)程式又小了幾K.

6.給exe加殼.
使用exe加殼程式給程式加個殼也是減小體積的一個好方法.
我常用的是upx,如果前面的節對齊的值大於512的話,就可以使用upx進行加殼壓縮.
通常可以壓縮至原大小的66%左右.

7.折中的辦法:

丟掉了CRT,重寫一些函數的工作量比較大,而且有些函數自己也寫不出來.(比如sin函數,像我這樣的
高數菜鳥拿著就頭痛)但確實有時候會用到這些函數.於是就有了以下的折中辦法:
VC6是98年推出的.它的動態連結程式庫版的dll是msvcrt.dll,因為出來的早,這個dll的裝機率十分的高.
(我以前學校的win98se都內建,98後的系統自然不用說了.)使用它基本可以不考慮部署時缺少dll的問題
所以可以使用這個dll提供的crt函數.要使用它,先得去找個vc6,複製裡面的msvcrt.lib,改個名.比如
vcrt6.lib然後把它添加到連結的庫裡.編譯的時候會有庫衝突的提示,直接無視即可.這樣既可以使用絕大
部分的CRT庫,又做到了減肥.還不用擔心會有找不到庫的情況.也不用再重新指定進入點.但是經我實驗發現
這樣編譯出來的程式還是會比完全丟掉CRT的大上一點,所以只是個折中的辦法.

接下來做下實驗:
寫一個簡單的程式:

C/C++ code
#include <windows.h> 
#include <stdio.h>
void main ()
{
char* str =newchar[250];
sprintf (str,"當前系統已運行了%d毫秒!",GetTickCount());
MessageBox (NULL,str,str,MB_ICONINFORMATION);
delete[] str;
}

然後做下編譯(VC9的編譯器,未更改節對齊值,未做加殼)
靜態CRT:50KB
動態連結CRT:5.50KB
使用VC6的動態連結CRT:3.00 KB

完全不用CRT要做下更改:

C/C++ code
#include <windows.h> 
#pragma comment (lib,"user32.lib")
#pragma comment (lib,"kernel32.lib")
void*operatornew[] (unsigned int size)
{
return HeapAlloc (GetProcessHeap(),NULL,size);
}
voidoperator delete[] (void* memblock)
{
HeapFree (GetProcessHeap(),NULL,memblock);
}
#define sprintf wsprintf
void main ()
{
char* str =newchar[250];
sprintf (str,"當前系統已運行了%d毫秒!",GetTickCount());
MessageBox (NULL,str,str,MB_ICONINFORMATION);
delete[] str;
}

編譯參數也比較長:
cl /MD msgbox.cpp /link /nodefaultlib:msvcrt.lib /entry:main
編譯後大小:2.00KB
加上/align:16編譯後大小:960Byte

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.