FAQ C/C++ Compilers [23.02.97]

Archive-name: ru/lang/compiler.cpp
Posting-Frequency: weekly
Last-modified: 1997/02/23

Добрый день, уважаемый почитатель языков C и C++!

     Перед Вами - сборник часто задаваемых вопросов и ответов к ним по
компиляторам языков C и C++. *Пожалуйста*, постарайтесь прочесть этот
список перед тем, как задавать вопросы в конференции, особенно если Вы
подозреваете, что Ваш вопрос из регулярно задаваемых. *Спасибо*!


*NB*

- Данный лист распространяется как freeware и на манипуляции над ним нет
  ограничений - трите, конвертируйте, распространяйте дальше, можно даже
  отлить скрижали. Единственная просьба: ссылайтесь на авторов при
  цитировании.

- Последние редакции этого FAQ List распространяются в конференции
  relcom.fido.su.c-c++ (миррор Фидо-эхи su.c_cpp) _пока_ на еженедельной
  основе. Также его можно получить на майл-серверах, поддерживающих
  хранение FAQ - имя архива смотрите в первых строках в Archive-name.

- Базовая WWW-страница для этого FAQ List расположена по URL
  http://soft.munic.msk.su/.

- Александр Кротов ведёт посвящённую конференции relcom.fido.su.c-c++
  WWW-страницу, на которой можно найти также и этот FAQ List по URL
  http://such.srcc.msu.su/cplus/.

- Этот FAQ List содержит только часть ответов - ответы на вопросы по языкам
  и библиотекам содержатся в двух других листах.

- Для облегчения поиска новых ответов в начале каждого ответа после имени
  автора указывается дата последней модификации.


*History*

06.02
- Добавлен вопрос про вызов методов объекта из ассемблера

12.10
- Добавлен вопрос про "Null pointer assignment" в BC++
- Добавлен вопрос про проблемы с загрузкой .DLL в BC++

23.02.97
- Добавлено два замечания про генерацию внешних имён
- Добавлено замечание про метки во встроенном ассемблере в BC++
- Расширен ответ про "глюки" в BC++ 3.1
- Добавлен вопрос про работу отладчика в IDE BC++ 3.1
- Добавлен вопрос про переполнение стека


*Содержание*
(* - есть модификации; + - есть добавления)

* Как вызвать метод объекта C++ из ассемблера или из C
+ Что есть stack overflow и как с этим бороться
- Есть ли в Watcom встроенный ассемблер?
- Где в Watcom библиотека doscalls.lib?
* BC не хочет понимать метки во встроенном ассемблере
* Редактирование исходников и исчезновение глюков в BC++
- Что значит "Null pointer assignment"
- Проблемы с запуском программы вне среды в BC++ под Windows
+ Почему инспектор в BC++ ругается на inactive scope


==============================================================================
/------/
> Q: Понадобилось написать метод объекта на ассемблере, а ватком строит
>    имена так, что это невозможно - стоит знак ':' в середине метки, типа
>    xcvvxx:svvsvv. Какие ключи нужны чтобы он такого не делал?

A: (Vadim Gaponov) - 06.02.96

        class A;
        extern "C" int ClassMetod_Call2Asm(A*, ...);

        class A {
                int Call2Asm(...) { return ClassMetod_Call2Asm(this, ...); }
        };

Сожрет _любой_ Cpp компилятор :). Для методов, которые ты хочешь вызывать
_из asm_ - аналогично...

A: (Kirill Joss) - 23.02.97

     Только что прочитал в .HLP (Compiler Guide Online Help), как можно
произвольно менять генерацию имён в Watcom:

        #pragma aux var "_*";

и var будет всегда генериться как _var. А ещё лучше в данном случае
использовать extern "C" и для переменных также.

A: (Dmitry Kazachkov) - 23.02.97

     _ после имени функции говорит о том, что Вaтком использует передaчу
пaрaметров в регистрaх. От этого помогaет cdecl перед именем функции.

Пример:
extern "C" int cdecl my_func();
|       |        |
|       |  способ передaчи aргументов: для С это через стек, последний
|       |  aргумент идет в стек первым; Вaтком по умолчaнию передaет в
|       |  регистрaх и подчерк для тaких функциий генерирует после имени
|       |
|  директивa не декорировaть имя, кaк и в С (стандартная)
|
a это про то, что функция описaнa в другом модуле (тоже стандартная)


/------/
> Q: Скажите почему возникает stack overflow и как с ним бороться

A: (Vadim Bugrov) - 23.02.97

     Причины:

1) велика вложеность функций
2) слишком много локальных переменных (или большие локальные массивы)
3) велика глубина рекурсии (например, по ошибке рекурсия бесконечна)
4) используется call-back от какого-то драйвера (например, мыши)

     пп. 1-3 - проверить на наличие ошибок, по возможности сделать массивы
статическими или динамическими вместо локальных, увеличить стек через
_stklen (для BC++), проверять оставшийся стек самостоятельно путем
сравнения _stklen с регистром SP.

     п.4 - в функции, использующей call-back, не проверять стек; в связи с
тем, что он может быть очень мал - организовать свой.


/------/
> Q: Любители Ватсона! А че, у него встроенного ассемблера нет что-ли?
>    Конструкции типа asm{} не проходят :(

A: (Vlad Bulatov) - 27.12.95

     Встроенного asm'a у него на самом деле нет. Есть правда возможность
писать asm-функции через '#pragma aux ...'. Hапример:

        #pragma aux DWordsMover =         \
                "mov esi, eax",           \
                "mov edi, ebx",           \
                "jcxz @@skipDwordsMover", \
                "rep movsd",              \
                "@@skipDWordsMover:",     \
                parm [ebx] [eax] [ecx] modify [esi edi ecx]

        void DWordsMover(void* dst, void* src, size_t sz);


/------/
> Q: При создании 16-bit OS/2 executable Watcom требует либу DOSCALLS.LIB.
>    Причем ее нет ни в поставке Ваткома ни в OS/2. Что это за либа и где
>    ее можно поиметь?

A: (Sergey Cremez) - 04.02.96

     Кличут ее теперь по другому. В каталоге LIB286 и LIB386 есть такая
OS2286.LIB. Это то, что тебе нужно. Обзови ее DOSCALLS.LIB и все.


/------/
> Q: BC не хочет понимать метки в ассемблерной вставке - компилятор сказал,
>    что не определена энта самая метка. Пришлось определить метку за
>    пределами ASM-блока. Может быть есть более корректное решение?

A: (Michael Yutsis) - 27.12.95

     Загляни в исходники RTL от BC++ 3.1 и yвидишь там нечто красивое,
например:

        #define I asm
        //........
        I   or si,si
        I   jz m1
        I   mov dx,1
        m1:
        I   int 21h

и т.д.

A: (Vadim Gaponov) - 06.01.96

     Есть - компилировать с ключом '-B' (via Tasm) aka '#pragma inline'.
Правда, при этом могут возникнуть другие проблемы: если присутствуют имена
read и _read (например), то компилятор в них запутается :).

     BTW: Было замечено, что борланд (3.1, например) иногда генерит разный
код в зависимости от ключа -B. Как правило, при его наличии он становится
"осторожнее" - начинает понимать, что не он один использует регистры.

A: (Victor Pomortseff) - 23.02.96

     В документации по BC 3.1 я нашёл то место, где описано использование
меток в inline assembler.

Borland C++ version 3.1 Programmer's Guide.
Chapter 12. BASM and inline assembly,
Using jump instructions and labels, p.406.

You can use any of conditional and unconditional jump inctructions, plus
the loop instructions, in inline assembly. They are only valid inside a
function. Since no labels can be defined in the `asm` statements, jump
instruction must use C `goto` labels as the object of the jump. If the
label is too far away, the jump will be automatically converted to a
long-distance jump. Direct far jumps cannot be generated.

In the following code, the jump goes to the C `goto` label "a".

        int x(){
            a:          /* This is the goto label "a" */
            ...
            asm jmp a   /* Goes to label "a" */
            ...
        }

Indirect jumps are also allowed. To use an indirect jump, you can use a
register name as the operand of the jump instruction.


/------/
> Q: Прошу прощения, но глюк пропал сам собой! Только что вернул назад
>    исходный текст и глюка пропала. Hо ведь _была_. Правда я перелопатил
>    основательно исходник к тому времени. Похоже действительно дар :)

A: (Arkady Belousov) - 23.02.97

     Hа полном серьёзе - в Борланде это один из главных способов борьбы с
его глюкогенератором. Видимо, там есть какие-то неинициализированные
переменные. Я лично сталкивался с подобными плавающими глюками, когда
после некоторых манипуляций над исходниками в других местах листинг
менялся к лучшему (в смысле баг исчезал).

     С другой стороны, я сталкивался с глюком, когда скомпилированная
прога на моей машине при специальном наборе данных работала неправильно,
а на другой машине, или при другом наборе данных, или после неменяющей
результат перестановке операторов или даже вставке отладочного вывода в
проивольном месте глюк исчезал.

     Кстати, иногда здесь может быть доля и твоей вины - я однажды забыл в
хедере поставить ; после определения последнего класса, и из-за этого IDE
отваливал, а bcc выдавал GPF. И, поскольку у bcc по меньшей мере видно
последние сообщения, да и GPF обычно не приводит систему в нестабильное
состояние, я практически полностью перёл на bcc в одном окне Windows, и
thelp в другом.

     И последнее. Оптимизатор в Борланде никоим образом нельзя считать
полноценным - гарантированные глюки при компиляции для 386+ и возможные
глюки при прочих опциях. Я это наглядно наблюдал на работоспособности
окна со списком файлов в перекомпилированном TV (тогда использовался TVOS2
Ильфака Гильфанова со всеми применёнными багфиксами).


/------/
> Q: А почему при выходе из программы под BC++ 3.1 выскакивает "Null
>    pointer assignment"?

A: (Eugene Paderin) - 12.10.96

     Это ты попытался что-то записать по нулевому адресу памяти, чего
делать нельзя. Типичные причины:

1) используешь указатель, не инициализировав его. Hапример:

        char *string; gets(string);

2) запрашиваешь указатель у функции, она тебе возвращает NULL в качестве
ошибки, а ты этого не проверяешь. Hапример:

        FILE *f = fopen("gluck", "w"); putc('X', f);

     Это сообщение выдаётся только в моделях памяти Tiny, Small, Medium.
Механизм его возникновения такой: в сегменте данных по нулевому адресу
записан борландовский копирайт и его контрольная сумма. После выхода из
main контрольная сумма проверяется и если не совпала - значит нагажено по
нулевому адресу (или рядом) и выдаётся сообщение. Как отловить смотри в
HELPME!.DOC - при отладке в Watch поставить выражения:

        *(char*)0,4m
        (char*)4

потом трассировать программу и ловить момент, когда значения изменятся.
Первое выражение - контрольная сумма, второе - проверяемая строка.


/------/
> Q: При запуске программы из BC (Ctrl-F9) все работает нормально, а если
>    закрыть BC, то программа не запускается. Что делать?

A: (Jouri Mamaev) - 12.10.96

     Если используешь BWCC, то эту либу надо грузить самому - просто среда
загружает BWCC сама и делаёт её доступной для программы. Я пользую такой
макрос:

        #define _BEST EnableBWCC(TRUE); \
                      EnableCtl3d(TRUE); \
                      EnableCtl3dAutosubclass(TRUE)

Потом в InitMainWindow пишешь:

        _BEST;

и все путем. Вообще-то правильнее OWL-евые ексепшены ловить и выдавать
сообщение самостоятельно. Заодно и понятнее будет отчего оно произошло:

        int OwlMain(int /*argc*/, char* /*argv*/[]){
                int res;
                TRY{ res = App().Run(); }
                CATCH((xmsg &s) //Какие хочешь ексепшены
                        { MessageBox(NULL, "Message", s.c_str()); }
                return res;
        }


/------/
> Q: Почему иногда пытаешься проинспектировать переменную в BC++ во время
>    отладки, а он ругается на inactive scope

A: (Elijah Merkin) - 23.02.97

     Вот пример отлаживаемой программы. Компилил так: bcc -v is.cpp

=== Cut ===
        #include 
        void a(){
          int b = 7;
          cout << b << endl;
        }

        void main(){
          a();
        }
=== Cut ===

     Входим в TD. Hажимаем F8, оказываемся на строке с вызовом a().
Пытаемся inspect b. Естественно, не находим ничего. А теперь перемещаем
курсор в окне исходника на строку с cout, но трассировкой в a() не входим
и пробуем посмотреть b. И вот тут-то и получаем inactive scope.


/------/
==============================================================================
/FYI/

- За основу были взяты FAQ List эх SU.OS2.*, ведомые Дмитрием Завалишиным.
- GoldEd 0611 имеет режим расцветки отмеченных строк, используемый в данном
  FAQ List.
- Если Вы нашли ошибку или устаревшую информацию и готовы ее исправить,
  присылайте, пожалуйста, свой вариант соответствующей статьи. Желательно -
  полностью заменяющий оригинал.


_Спасибо_ всем, кто прислал статьи!    Arkady Belousov aka ark@munic.msk.su