Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Сабуров С.В. - Язык программирования C и C++ - 2006

.pdf
Скачиваний:
312
Добавлен:
13.08.2013
Размер:
1.42 Mб
Скачать

Тонкости и хитрости в вопросах и ответах

Моя программа аварийно завершается еще до выполнения! (если использовать отладчик, то видно, что смерть наступает еще до выполнения первой инструкции в main)

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

Часто предпочтительнее объявить большие массивы типа static (если, конечно, каждый раз при рекурсивном вызове не требуется свежий массив).

Что означают сообщения «Segmentation violation» и «Bus error»?

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

Моя программа аварийно завершается, очевидно, при выполнении malloc, но я не вижу в ней ничего плохого

К несчастью, очень легко разрушить внутренние структуры данных, создаваемые malloc, а возникающие проблемы могут быть трудны для отладки. Чаще всего проблемы возникают при попытке записать больше данных, чем может уместиться в памяти, выделенной malloc; особенно распространена ошибка malloc(strlen(s)) вместо strlen(s) + 1.

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

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

Где достать грамматику Си для программы YACC?

Самая надежная — конечно же грамматика из стандарта ANSI. Другая грамматика, подготовленная Джимом Роскиндом (Jim Roskind), находится на ics.uci.edu в директории pub/*grammar*. Одетый в плоть, работающий образец ANSI грамматики (принадлежащий Джефу Ли(Jeff Lee)) находится на

607

Тонкости и хитрости в вопросах и ответах

uunet в директории usenet/net.sources/ansi.c.grammar.Z (вместе с лексическим анализатором).

Мне необходим исходный текст для разбора и вычисления формул

Есть два доступных пакета — «defunc» и пакет «parse».

Мне необходима функция типа strcmp, но для приблизительного сравнения, чтобы проверить две строки на близость, но не на тождество

Обычно такие сравнения включают алгоритм «soundex», который ставит в соответствие сходно звучащим словам один и тот же числовой код. Этот алгоритм описан в томе «Сортировка и поиск» классической книги Дональда Кнута «Искусство программирования для ЭВМ».

Как по дате найти день недели?

Используйте mktime или попробуйте вот эту функцию:

dayofweek(y, m, d)

/*

0

= Воскресенье

*/

 

 

 

 

 

int y, m, d;

/* 1

<=

m

<=

12,

y

>

1752

(примерно)

*/

{

 

 

 

 

 

 

 

 

 

 

 

 

 

static int t[] = {0,

3,

2,

5,

0,

3, 5,

1,

4,

6,

2,

4};

y = m < 3;

 

 

 

 

 

 

 

 

 

 

 

 

 

return (y + y/4 —

y/100

+

y/400

+

t[m 1] +

d)

%

7;

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

Как произносить «char»?

Ключевое слово Си «char» можно произносить тремя способами, как английские слова «char», «care» или «car». Выбор за вами.

Какие есть хорошие книги для изучения Си?

Митч Райт (Mitch Wright) поддерживает аннотированную библиографию книг по Си и по UNIX; она доступна через ftp ftp.rahul.net в директории pub/mitch/YABL.

Как преобразовать AnsiString в char*?

У класса AnsiString есть метод, декларация которого выглядит так:

char* __fastcall c_str() const; E.g.: char a[10];

AnsiString b="CBuilder"; strcpy(a, b.c_str());

608

Тонкости и хитрости в вопросах и ответах

Как сделать, чтобы программа на CBuilder3,4 не требовала .bpl, .dll?

В Project Options Packages снять галку с Build with runtime packages; в Project Options Linker снять галку с Use dynamic RTL.

Что такое RXLib и где его взять?

Одна из самых, если не самая лучшая библиотека общего назначения для Delphi. Огромное количество компонентов и полезных функций. Полные исходные тексты. Совместима со всеми Delphi, а также с C++Builder. Великолепные примеры использования. Исчерпывающие файлы помощи на русском языке.

Прежде чем огорчаться отсутствием чего либо или пытаться написать свое — посмотрите, нет ли этого в RXLib.

Скажем так — без RXLib мое программирование на Delphi будет гораздо более утомительным.

Как сделать, чтобы окно вело себя, как верхняя панель в билдере, т.е. pесайзилось только по горизонтали, и только до определенного минимального размера, а по вертикали размер был фиксированным?

Надо написать обработчик сообщения

WM_GETMINMAXINFO.

Например, так:

class TForm1 : public TForm

{

//...........

private:

void __fastcall WMGetMinMaxInfo(TMessage& Msg); BEGIN_MESSAGE_MAP

VCL_MESSAGE_HANDLER(WM_GETMINMAXINFO, TMessage, WMGetMinMaxInfo)

END_MESSAGE_MAP(TForm) };

void __fastcall TForm1::WMGetMinMaxInfo(TMessage&Mmsg)

{

(LPMINMAXINFO(Msg.LParam)) >ptMinTrackSize.x=200; (LPMINMAXINFO(Msg.LParam)) >ptMinTrackSize.y=Height; (LPMINMAXINFO(Msg.LParam)) >ptMaxTrackSize.y=Height;

Msg.Result=0;

}

609

Тонкости и хитрости в вопросах и ответах

В CB4 можно воспользоваться свойством Constraints.

Как организовать SplashScreen?

1.Посмотреть на $(BCB)\Examples\DBTasks\MastApp.

2.Воспользоваться функцией ShowSplashWindow(...) из

RXLib.

3.Написать руками:

а) Делаешь форму, которая будет изображать SplashScreen;

б) Делаешь WinMain вида:

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

{

try

{

SplashF=new TSplashF(Application); SplashF >Show(); SplashF >Update();

Application >Initialize();

//...

SplashF >Close(); delete SplashF;

Application >Run();

//...

Как засунуть иконку в system tray («туда, где часы» (c))?

1.Воспользоваться компонентом TRxTrayIcon из RXLib.

2.Посмотреть в хелпе описание на Shell_NotifyIcon(...).

3.Посмотреть на $(BCB)\Examples\Apps\TrayIcon (есть только в CB3,4).

4.Посмотреть на $(BCB)\Examples\Controls\Tray (CB4).

Как русифицировать Database Desktop 7?

[HKEY_CURRENT_USER\Software\Borland\DBD\7.0\Preferences\ Properties]

"SystemFont"="MS Sans Serif"

или

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\ CodePage]

610

Тонкости и хитрости в вопросах и ответах

"1252"="c_1251.nls"

И все!!! Никаких проблем с «иероглифами» в любых программах!

Из!за чего может виснуть С++Builder 3 под Windows 98 (при запуске)? Он запускался в Windows 95 при 16 цветах, а в Windows 98 никак не хочет

Надо либо убавлять Hardware Acceleration, либо менять драйверы.

[HKEY_CURRENT_CONFIG\Display\Settings] "BusThrottle"="on"

Почему в билдере размер структуры всегда растягивается до кратного 4!ем?

Из за выравнивания (RTFM Data Alignment).

Чтобы поля структуры выравнивались на 8 ми битную границу, необходимо использовать следующую конструкцию:

#pragma pack(push, 1) <structure definition> #pragma pack(pop)

Менять выравнивание для всего проекта (Project Options\Advanced Compiler\Data Alignment) не рекомендуется.

Какой!нибудь из CBuilder'ов умеет делать win16 Exe?

Нет.

Как создать компонент по его имени?

#include <typeinfo.h> #include <stdio.h> class A {

public:

virtual A *Create(void) = 0;

};

class B1 : A { public:

B1();

A *Create(void) { return(new B1); }

};

class B2 : A { public:

B2();

611

Тонкости и хитрости в вопросах и ответах

A *Create(void) { return(new B2); }

};

B1::B1() { printf("Create B1\n"); }

B2::B2() { printf("Create B2\n"); }

// Собственно "создатель"

A *CopyCreate(A *a)

{

if(a && typeid(A).before(typeid(a))) return(a >Create()); else printf("Illegal call\n");

return(NULL);

}

// дальше пример использования

void main( void )

{

B1 *b1 = new B1;

B2 *b2 = new B2;

printf("Call test b1\n"); B1 *bb1 =

dynamic_cast<B1*>(CopyCreate(reinterpret_cast<A*>(b1))); printf("Call test b2\n");

B2 *bb2 = dynamic_cast<B2*>(CopyCreate(reinterpret_cast<A*>(b2)));

delete b; delete bb2; delete b1; delete b2;

}

pезyльтат запyска

G:\PROJECT.BC5\Test>a.exe Create B1

Create B2 Call test b1 Create B1 Call test b2

612

Тонкости и хитрости в вопросах и ответах

Create B2

Естественно для «полной кyльтypности» надо понавставлять try/catch или перекрыть Bad_Cast, но это уже детали.

Еще один способ:

class TComponent1* : public TComponent

{

// Это класс от которого мы будем порождать все наши классы public:

__fastcall TComponent1( TComponent* Owner ):TComponent(Owner){}

virtual TComponent1* __fastcall Create(TComponent* Owner)=0;

}

class TMyClass1 : public TComponent1

{

public:

__fastcall TMyClass1(TComponent* Owner): TComponent1(Owner){}

virtual TMyClass1* __fastcall Create(TComponent* Owner) {return new TMyClass1(Owner);}

// Эта функция создает класс, поскольку все создаваемые классы мои и порождены от TObject проблем нет, осталось только ее вызвать.

}

Вот функция для создания класса:

TComponent1* __fastcall CreateClass( AnsiString ClsName, TComponent* Owner )

{

TClass cls = GetClass( clsName );

//Это сработает если класс зарегистрирован функцией RegisterClasses в инициализации модуля

void * mem = SysGetMem( InstanceSize(cls) ); TComponent1* Result = InitInstance(cls, mem); Result = Result >Create( Owner );

//Класс создан правильно и его можно вернуть освободив память

613

Тонкости и хитрости в вопросах и ответах

SysFreeMem( mem ); return Result;

}

Если список классов, которые надо создавать по имени, не очень велик, то можно так:

TControl* CreateControlByName(AnsiString ClassName, TComponent *Owner)

{

TMetaClass *c=GetClass(ClassName); if(c==NULL)

throw Exception("Unregistered class."); if(c==__classid(TButton))

return new TButton(Owner); if(c==__classid(TEdit))

return new TEdit(Owner); return NULL;

}

Почему функция isdigit (да и остальные is*) возвращает некорректные значения для аргумента в виде русской буквы?

Напиши #undef isdigit, будет вызываться функция с правильным кастингом.

Почему при сборке в CB3 с включенным Build With Runtime Packages все работает, а если отключить, то вылетает с ошибкой, не доходя до Application!>Initialize()?

В IDE есть глючек, в результате которого порядок .lib в строке LIBRARIES .bpr файла оказывается неправильным (первым обязательно должен идти vcl35.lib). Из за этого нарушается порядок инициализации модулей и глобальных VCL объектов. В результате при запуске программы имеем стабильный Access Violation. Для его устранения необходимо поправить строку ALLLIB .bpr файла:

ALLLIB = vcl35.lib $(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib

Есть функция, которая производит длительные вычисления в цикле. Хотелось бы иметь возможность ее прервать. Естественно, что пока вычисления не выходят из цикла никакие контролы не работают...

Вставить в цикл, в котором происходят вычисления, вызов

Application >ProcessMessages(); Т.е.:

for(.....

{

614

Тонкости и хитрости в вопросах и ответах

//здесь выполняются вычисления Application >ProcessMessages();

}

Также вынести вычисления в отдельный thread.

Я переписываю BDE!приложение на другой компьютер, а оно отказывается работать. Что делать?

1.Использовать инсталляционный пакет, например

InstallShield или Wise.

2.Не использовать его. В этом случае нет универсального решения.

Оно будет варьироваться в зависимости от использования BDE в локальном или серверном режиме, для доступа к Paradox или DBF таблицам, использования локального SQL, версии BDE, и так далее... Здесь приведен пример для наиболее общего варианта — пятая версия BDE, локальные таблицы, без использования локального SQL, стандартная кодировка ANSI.

Нужно добавить следующие файлы из папки BDE к вашему исполняемому модулю: blw32.dll, idapi32.dll, idr20009.dll, idpdx32.dll для Paradox таблиц или iddbas32.dll для DBF таблиц, bantam.dll, charset.cvb, usa.btl.

Доступ к таблицам надо настроить не через псевдонимы (alias'ы), а через пути в файловой системе. В идеале все таблицы храните в папке программы, тогда нужно только указать имя таблицы без пути.

Приготовленный таким образом дистрибутив запускается на любой машине без необходимости инсталляции BDE, максимально устойчив и нечувствителен к смене имен папок/переинсталляции системы/порчи реестра/влиянии на другие BDE приложения. Добавка к основному модулю составляет для этих семи dll библиотек ~1030 КБ, после упаковки ~470 КБ.

Для того, чтобы установить программу, которая требует BDE, есть несколько базовых путей, в частности:

1. Создать полноценную программу инсталляции с помощью продуктов Install Shield, Wise или подобных. Указанные продукты используются чаще всего и оба позволяют включить в инсталляцию BDE + базовые настройки (алиасы и пути).

615

Тонкости и хитрости в вопросах и ответах

2.Для разных целей можно сделать инсталляцию BDE отдельным пакетом (в Install Shield'е это делается более чем элементарно — в проект не надо добавлять ничего, кроме поддержки BDE). Удобно в процессе написания программы для одного пользователя. Первый раз устанавливаешь и настраиваешь BDE, а затем носишь только новые версии программ. Так же можно при установке Дельфи/Билдеpа с компашки снять флажки отовсюду кроме BDE — в этом случае будет установлена только BDE.

3.Есть возможность инсталлировать BDE ручками. Первый этап — копирование файлов, второй — прописывание реестра.

Теперь к вопросу о том, почему установка BDE — это не просто прописать одну опцию в проекте.

Дело в том, что BDE — это не просто несколько библиотек динамического доступа (DLL), это — целый engine, достаточно хорошо продуманный для того, чтобы быть и универсальным и расширяемым. Занимает он в запакованном виде две дискеты, а в распакованном (+ файлы, которые включать в поставку не нужно) — более десяти!

Естественно, не для всех задач подходит именно BDE (благодаря своим особенностям). Во первых, возникают проблемы при работе с DBF форматов Clipper и Fox. Во вторых, не для всех программ требуются все возможности BDE, а быть они должны как можно меньше.

Как из Builder'a можно работать с последовательными портами?

Существует компонент ZComm (free for personal use), поддерживает все порты, все скорости, hard/soft flow control, in/out буферизацию. Передача/прием данных вынесены в отдельную нитку.

Еще один вариант:

__fastcall TComPort::TComPort(TComponent* Owner) : TComponent(Owner)

{

OverlappedStructure.Offset

=

0;

OverlappedStructure.OffsetHigh

=

0;

OverlappedStructure.hEvent

=

0;

iComNumber

=

2;

 

 

iBaudRate

=

9600;

 

 

616

Соседние файлы в предмете Программирование на C++