// stub.cpp – the "mini-CRT" implementation file
void* __cdecl malloc(size_t n) {
void* pv = HeapAlloc(GetProcessHeap(), 0, n);
return pv;
}
void* __cdecl calloc(size_t n, size_t s) {
return malloc(n*s);
}
void* __cdecl realloc(void* p, size_t n) {
if (p == NULL) return malloc(n);
return HeapReAlloc(GetProcessHeap(), 0, p, n);
}
void __cdecl free(void* p) {
if (p == NULL) return;
HeapFree(GetProcessHeap(), 0, p);
}
void* __cdecl operator new(size_t n) {
return malloc(n);
}
void __cdecl operator delete(void* p) {
free(p);
}
Вот пример программы, которая будет спокойно собрана с помощью такого подхода без стартового кода CRT:
#include
#include "stub.cpp"
#include
typedef std::map IntMap;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
IntMap m;
for (int j=0; j<100; j++) m[j*j]=j;
IntMap::iterator i=m.find(49);
MessageBox(0, (i==m.end()) ? "49 was not found" : "49 was found", "std::map test", MB_OK);
return 0;
}
Для сборки этого примера необходимо использовать следующую командную строку:
cl test.cpp user32.lib kernel32.lib /link /nod /opt:nowin98 /subsystem:windows /entry:WinMain
Библиотека импорта kernel32.lib необходима для функций работы с Win32-кучей.
Что касается других реализаций STL, предоставлю слово Павлу Блудову:
Страшная тайна STL от SGI и HP в том, что им совершенно не нужна CRT.
С двумя оговорками:
1. Не используется C++ Exception Handling
2. (Вытекает из первой) определен макрос __THROW_BAD_ALLOC, например, так:
#ifndef _CPPUNWIND
#define __THROW_BAD_ALLOC \
::MessageBox(NULL, _T("STL: Out of memory."), NULL, MB_OK | MB_ICONSTOP); \
::ExitProcess(-5);
#endif _CPPUNWIND
#include
если посмотреть на __THROW_BAD_ALLOC, то он являет собой
#define __THROW_BAD_ALLOCfprintf(stderr, "out of memory\n"); exit(1)
именно эта строчка, и никакая другая, нуждается в CRT. Ну, если быть совсем точным, std::string'у может понадобиться CRT. Тут уж ничего не попишешь. Используйте WTL::CString.
Павел.
Слова о std::string в полной мере справедливы и для реализации STL от Dinkumware. Если вы ищете реализацию полноценного строкового класса, не использующего стартовый код CRT, советую взглянуть на CascStringв составе библиотеки ascLib.
Директива #import и ее ограничения в облегченных проектах
Частой причиной появления зависимости от CRT является необдуманное применение директивы #import– расширения visual c++ для удобства работы с COM-объектами, предоставляющими библиотеки типов. Подробнее о ней можно прочитать в MSDN, а на русском языке – в статье Игоря Ткачева "Использование директивы #import в Visual C++".
При ее использовании компилятор генерирует описания интерфейсов и, если не указано обратное, создает набор оберточных классов ( wrappers ) для упрощения работы с указателями на эти интерфейсы. Кроме того, детали реализации COM-объектов скрываются за высокоуровневыми средствами. В число таких деталей входят преобразование [out,retval]-параметров в возвращаемые значения функций, упрощение работы с BSTR-строками, управление сроками жизни объектов, доступ к свойствам и преобразование COM-HRESULT в исключения C++. Но поддержка всех этих приятных "мелочей" реализована с использованием CRT и требует включения стартового кода CRT.
Директива #import, несомненно, полезна для C++-программиста – ведь иначе, не имея описания интерфейсов, пришлось бы извлекать необходимую информацию вручную с помощью утилит типа OleView. Эту директиву можно применять и в проектах, не использующих CRT, но с рядом ограничений. В частности, необходимо подавить создание оберточных классов и трансляцию типов COM в классы-обертки _com_ptr, _com_error, _variant_t и _bstr_t. Вот пример выверенного использования #import, которое не "потянет" за собой половину кода CRT:
#import "file.dll" no_namespace, \
named_guids, no_implementation, \
raw_interfaces_only, raw_dispinterfaces, \
raw_native_types
Иногда при использовании #import можно обойтись "малой кровью". Это возможно, например, если в интерфейсах импортируемой библиотеки типов не используются BSTR– и VARIANT-параметры (вообще-то, достаточно редкий случай). Тогда можно воспользоваться всеми удобствами, предоставляемыми #import, но подавить генерацию исключений C++ при возврате ошибок. Для этого потребуется реализовать функцию
void __stdcall _com_issue_error(HRESULT hr);
Такая возможность определяется в каждом конкретном случае экспериментально. Все же, если вы не используете исключения, лучше отказаться от расширенной помощи директивы #import и обрабатывать HRESULT вручную.
ПРИМЕЧАНИЕ
В составе уже упомянутой библиотеки ATL/AUX есть средство автоматической генерации классов из библиотек типов, которое более пригодно для сверхмалых проектов, чем директива #import.
Читать дальше