При компиляции VC++ 2002 "хелло, ворлда" с "агрессивной оптимизацией" создается ехе-файл размером около 1 КБ: Код (Text): #include <windows.h> #pragma comment(linker,"/MERGE:.rdata=.text") #pragma comment(linker,"/ALIGN:512") #pragma comment(linker,"/ENTRY:Main") #pragma comment(linker,"/NODEFAULTLIB:LIBCMT /NODEFAULTLIB:OLDNAMES") void Main(){ MessageBox(0, "Hello, world!", "proj", MB_ICONASTERISK); ExitProcess(0); } Но стоит только вынести "Hello, world!" в массив: Код (Text): void Main(){ char buff[128] = "Hello, world!"; MessageBox(0, buff, "proj", MB_ICONASTERISK); ExitProcess(0); } EXEшник увеличивается до 7 с хвостом килобайт, причем добавленный код не похож на CRT, импортирует непонятно зачем следующие функции: VirtualAlloc HeapFree QueryPerformanceCounter GetTickCount GetCurrentThreadId GetCurrentProcessId GetSystemTimeAsFileTime RtlUnwind HeapReAlloc HeapAlloc Что делает этот код, чем объясняется подобное поведение компилятора и как избежать его включения? Кроме того, если вместо #pragma comment(linker,"/NODEFAULTLIB:LIBCMT /NODEFAULTLIB:OLDNAMES") использовать просто #pragma comment(linker,"/NODEFAULTLIB") , компилятор ругается на error LNK2019: unresolved external symbol ___security_cookie referenced in function "void __cdecl Main(void)" (?Main@@YAXXZ) Что такое security cookie в данном случае и зачем он нужен?
Должно быть, включена проверка переполнения буфера (/GS). Также советую отключить отладочную информацию в свойствах линкера, включить string pooling (/GF) и объединение секций (/MERGE:".rdata=.text"). Кстати, если вынести "Hello, world" в локальную переменную-массив, то генерируется ненужный код для копирования строки, заполнения буфера нулями (rep stosd) и выделения памяти на стеке. Лучше вынести в глобальную переменную, причем сделать ее константой: Код (Text): const char buff[128] = "Hello, world!"; void Main() { MessageBox(0, buff, "proj", MB_ICONASTERISK); ExitProcess(0); } _700290280__testw.rar
Зачем глобальная переменная? Код (Text): void Main(){ [b]static[/b] char buff[] = "Hello, world!"; // char * buff = "Hello, world!"; MessageBox(0, buff, "proj", MB_ICONASTERISK); ExitProcess(0); } ___security_cookie отключается /GS-
#pragma comment(linker, "/ENTRY:start") void start() { } или __declspec(naked) void start(void) { } и не нужно рантайм отключать, просто не нужно использовать стандартные С'шные функции и исключения
Со static получается 1,5 Кб, а не 1 Кб, т.к. неконстантные переменные (господи, тавтология-то какая! помещаются в отдельную секцию .data, а константы идут в ту же .text, что и код. Нужно делать static const: Код (Text): void Main(){ static const char buff[] = "Hello, world!"; MessageBox(0, buff, "proj", MB_ICONASTERISK); ExitProcess(0); } Asterix: А по-моему, лучше /ENTRY:start указывать в опциях линкера для Release-версии (см. файл выше). Тогда и отладочная версия будет работать, и можно будет без переделки перекомпилировать исходник другим компилятором, например, MinGW.
Будет там ноль. Даже Код (Text): static const char buff[13] = "Hello, world!"; ни один соответствующий стандарту компилятор не пропустит.
А вот ещё один прибабах от vc++ (на этот раз vc 7.0): Код (Text): //==================================================================== == static int* alloc( int dwSize ){ return (int*) VirtualAlloc( NULL, dwSize, MEM_COMMIT, PAGE_READWRITE ); } //==================================================================== == static void free( int* lpArray, int dwSize ){ VirtualFree ( (LPVOID) lpArray, dwSize, MEM_DECOMMIT ); } //==================================================================== == static int nrandom (int base){ int x; _asm { mov eax, nrandom_seed test eax, 80000000h jz _F add eax, 7fffffffh _F: xor edx, edx mov ecx, 127773 div ecx mov ecx, eax mov eax, 16807 mul edx mov edx, ecx mov ecx, eax mov eax, 2836 mul edx sub ecx, eax xor edx, edx mov eax, ecx mov nrandom_seed, ecx div base mov x, edx } return x; } //==================================================================== == void main(){ int* array; int* temp_array; array = alloc( size*4 ); temp_array = alloc( temp_size*4 ); for ( int i=0; i<temp_size; i++ ) temp_array[i]=nrandom(i); ....... ....... free(array, size); free(temp_array, temp_size); return; } При компиляции с /Ox компилятор с умным видом инлайнит ф-ций alloc, free, nrandom. Вроде всё правильно - ф-ции небольшие, требуется скорость - но есть одно но: кроме тех мест, где вставлены инлайном, эти ф-ции также попали в ехе отдельными ф-циями за пределами main, хотя они больше нигде не вызываются, только из main. Зачем дублировать код?
S_T_A_S_ и давно ? мне помнится что при инициализации массива компилятор ничего не добавляет ,и это правильно по идее. но я могу и ошибаться ...
staier > и давно ? C тех пор, как производители компилятора решат не нарушать стандарт: 8.5.2 Character arrays [dcl.init.string] 1 A char array (whether plain char, signed char, or unsigned char) can be initialized by a stringliteral (optionally enclosed in braces); a wchar_t array can be initialized by a wide string-literal (optionally enclosed in braces); successive characters of the string-literal initialize the members of the array. [Example: Код (Text): char msg[] = "Syntax error on line %s\n"; shows a character array whose members are initialized with a string-literal. Note that because ’\n’ is a single character and because a trailing ’\0’ is appended, sizeof(msg) is 25. ] 2 There shall not be more initializers than there are array elements. [Example: Код (Text): char cv[4] = "asdf"; // error is ill-formed since there is no space for the implied trailing ’\0’. ] staier > мне помнится что при инициализации массива компилятор ничего не добавляет, и это правильно по идее. Компилятор _ничего_ не добавляет, а инициализирует тем, чем просят. hint: try sizeof("Hello, world!") Можно же и так инициализировать: Код (Text): static const char buff[] = 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!';
То, что ключами и инлайнами можно добиться я знаю. Дело то не в этом - почему присутствует функция, которая не вызывается?? Если сделать функцию, которая вообще не вызывается из исходника, то он её не включит в ехе. А если он проинлайнил, то сунет два раза Где логика?
мне кажется на самом деле логика есть компилятору по фиг есть в этом obj main или нет , это линкеру интересно. линкуется весь obj, вот если ты вынесешьв отдельный файл эти функции , то может и не прилинкует их в не inline теоретически это можно отследить , но насколько я знаю , smartlinking только в delphi есть
cresta > Где логика? Логика такая - без /Gy компилятор пихает все функции из исходного файла в объектник одним куском, линкер этот один кусок далее пихает в экзешник, выкидывать какой-то код он не имеет права. С ключём /Gy объектник содержит "отдельно" скомпилированные ф-ции, поэтому линкер уже может выкидывать неиспользуемое.