MyBooks.club
Все категории

А. Григорьев - О чём не пишут в книгах по Delphi

На сайте mybooks.club вы можете бесплатно читать книги онлайн без регистрации, включая А. Григорьев - О чём не пишут в книгах по Delphi. Жанр: Программирование издательство -,. Доступна полная версия книги с кратким содержанием для предварительного ознакомления, аннотацией (предисловием), рецензиями от других читателей и их экспертным мнением.
Кроме того, на сайте mybooks.club вы найдете множество новинок, которые стоит прочитать.

Название:
О чём не пишут в книгах по Delphi
Издательство:
-
ISBN:
-
Год:
-
Дата добавления:
17 сентябрь 2019
Количество просмотров:
245
Читать онлайн
А. Григорьев - О чём не пишут в книгах по Delphi

А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание

А. Григорьев - О чём не пишут в книгах по Delphi - описание и краткое содержание, автор А. Григорьев, читайте бесплатно онлайн на сайте электронной библиотеки mybooks.club
Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.Для программистов

О чём не пишут в книгах по Delphi читать онлайн бесплатно

О чём не пишут в книгах по Delphi - читать книгу онлайн бесплатно, автор А. Григорьев

Если не существует ограничения на длину возвращаемой строки, программа "не знает", буфер какого размера потребуется. Наиболее простое решение этой проблемы следующее: программа сначала вызывает функцию GetString, передавая nil в качестве указателя на буфер и 0 в качестве размера буфера. Затем по результату функции определяется требуемый размер буфера, выделяется память и функция вызывается еще раз, уже с буфером нужного размера. Такой способ обеспечивает правильную передачу строки любой длины, но требует двукратного вызова функции, что снижает производительность, особенно в том случае, если на формирование строки тратится много времени.

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

Листинг 3.45. Быстрый (в среднем) способ получения строки через буфер

const

 StatBufSize = ...; // Размер, подходящий для данного случая

var

 StatBuf: array[0..StatBufSize - 1] of Char;

 Buf: PChar;

 RealLen: Integer;

begin

 // Пытаемся разместить строку в буфере StatBuf

 RealLen := GetString(StatBuf, StatBufSize);

 if RealLen > StatBufSize then

 begin

  // Если StatBuf оказался слишком мал, динамически выделяем буфер

  // нужного размера и вызываем функции еще раз

  Buf := StrAlloc(RealLen);

  GetString(Buf, RealLen);

 end

 else

  // Размера статического буфера хватило. Пусть Buf указывает

  // на StatBuf, чтобы нижеследующий код мог в любом случае

  // обращаться к буферу через переменную Buf

  Buf := StatBuf;

 // Что-то делаем с содержимым буфера

 ...

 // Если выделяли память, ее следует очистить

 if Buf <> StatBuf then StrDispose(Buf);

end;

Следует также упомянуть о еще одной альтернативе передачи строк в DLL — типе WideString, который хранит строку в кодировке Unicode и является, по сути, оберткой над системным типом BSTR. Работать с WideString так же просто, как и с AnsiString, перекодирование из ANSI в Unicode и обратно выполняется автоматически при присваивании значения одного типа переменной другого. В целях совместимости с СОМ и OLE при работе с памятью дли строк WideString используется специальный системный менеджер памяти (через API-функции SysAllocString, SysFreeString и т.п.), поэтому передавать эти строки из DLL в главный модуль и обратно можно совершенно безопасно даже без ShareMem. Правда, при этом не стоит забывать о расходовании процессорного времени на перекодировку, если основная работа идет не с Unicode, а с ANSI.

Отметим одну ошибку, которую делают новички, прочитавшие комментарий про ShareMem, но не умеющие работать с PChar. Они пишут, например, такой код для функции, находящейся в DLL и возвращающей строку (листинг 3.46).

Листинг 3.46. Неправильный способ возврата строки из DLL

function SomeFunction(...): PChar;

var

 S: string;

begin

 // Здесь присваивается значение S

 Result := PChar(S);

end;

Такой код компилируется и даже, за редким исключением, дает ожидаемый результат. Но тем не менее, в этом коде грубая ошибка. Указатель, возвращаемый функцией, указывает на область памяти, которая считается свободной, поскольку после выхода переменной S за пределы области видимости память, которую занимала эта строка, освободилась. Менеджер памяти может в любой момент вернуть эту память системе (тогда обращение к ней вызовет Access violation) или задействовать для других целей (тогда новая информация уничтожит содержащуюся там строку). Проблема маскируется тем, что обычно результат используется немедленно, до того как менеджер памяти что-то сделает с этим блоком. Тем не менее полагаться на это и писать такой код не следует.

3.4. Прочие "подводные камни"

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

3.4.1. Порядок вычисления операндов

Эта проблема связана с тем, что у человека есть определенные интуитивные представления о порядке выполнения действий программой, однако компилятор не всегда им соответствует. Рассмотрим следующий код (листинг 3.47, пример OpOrder на компакт-диске).

Листинг 3.47. "Неправильный" порядок вычисления операндов

var

 X: Integer;


function GetValueAndModifyX: Integer;

begin

 X := 1;

 Result := 2;

end;


procedure TForm1.Button1Click(Sender: TObject);

var

 A1, A2: Integer;

begin

 X := 2;

 A1 := X + GetValueAndModifyX;

 X := 2;

 А2 := GetValueAndModifyX + X;

 Label1.Caption := IntToStr(A1);

 Label2.Caption := IntToStr(A2);

end;

Суть этого примера заключается в том, что функция GetValueAndModifyX имеет побочный эффект — изменяет значение глобальной переменной X. И эту же переменную мы используем при вычислении выражения, в которое входит также вызов GetValueAndModifyX. При вычислении A1 в выражении сначала упоминается X, а потом GetValueAndModifyX, при вычислении А2 — наоборот. Логично было бы предположить, что A1 получит значение 4, А2 — 3, т.к. вычисление первого операнда должно выполняться раньше второго. В действительности же обе переменные получат значение 3, поскольку компилятор сам выбирает порядок вычисления операндов независимо от того, в каком порядке они упоминаются в выражении. То же самое касается любых коммутативных операций: умножения, арифметических and, or и xor. Посмотрим, что будет для некоммутативных операций, например, для деления (листинг 3.48).

Листинг 3.48. "Неправильный" порядок вычисления операндов при делении

procedure TForm1.Button2Click(Sender: TObject);

var

 A1, A2: Extended;

begin

 X := 2;

 A1 := X / GetValueAndModifyX;

 X := 2;

 A2 := GetValueAndModifyX / X;

 Label1.Caption := FloatToStr(A1);

 Label2.Caption := FloatToStr(A2);

end;

В результате выполнения этого кода A1 получает значение 0.5, A2 — 2, т.е. и здесь сначала вычисляется функция, а потом берется значение переменной X.

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

Примечание

Побочные эффекты в функциях настолько небезопасны, что в некоторых языках они полностью запрещены. Например, в Аде изменять значения глобальных переменных могут только процедуры, но не функции.

Ради интереса посмотрим, что будет, если вторым аргументом тоже будет функция, зависящая от X, (листинг 3.49).

Листинг 3.49. Сложение двух операндов с побочными эффектами

function GetX: Integer;

begin

 Result := X;

end;


procedure TForm1.Button3Click(Sender: TObject);

var

 A1, A2: Integer;

begin

 X:= 2;

 A1 := GetX + GetValueAndModifyX;

 X := 2;

 A2 := GetValueAndModifyX + GetX;

 Label1.Caption := IntToStr(A1);

 Label2.Caption := IntToStr(A2);

end;

Здесь A1 получит значение 4, A2 — 3, т.e. интуитивно ожидаемые. Тем не менее полагаться на интуицию все же не стоит: в более сложных случаях она может подвести. Дело в том, что стандарт языка Паскаль разрешает разработчикам конкретной реализации языка самим выбирать порядок вычисления операндов [5]. Поэтому, даже если вам удалось добиться желаемого порядка вычисления, в следующих версиях Delphi (или при переносе на другую платформу) программа может начать работать неправильно. Таким образом, разработчик не имеет права делать какие-то предположения о том, в каком порядке будут вычисляться операнды, а когда изменение этого порядка может повлиять на результат, код должен быть написан таким образом, чтобы исключить эту возможность. В частности, пример со сложением должен быть переписан так (листинг 3.50).


А. Григорьев читать все книги автора по порядку

А. Григорьев - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки mybooks.club.


О чём не пишут в книгах по Delphi отзывы

Отзывы читателей о книге О чём не пишут в книгах по Delphi, автор: А. Григорьев. Читайте комментарии и мнения людей о произведении.

Прокомментировать
Подтвердите что вы не робот:*
Подтвердите что вы не робот:*
Все материалы на сайте размещаются его пользователями.
Администратор сайта не несёт ответственности за действия пользователей сайта..
Вы можете направить вашу жалобу на почту librarybook.ru@gmail.com или заполнить форму обратной связи.