Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2002.09.12;
Скачать: [xml.tar.bz2];

Вниз

---|Ветка была без названия|---   Найти похожие ветки 

 
VEG   (2002-08-10 23:18) [0]

Безопасный код: Безопасность - прежде всего! Лучше заранее предохраниться от проблем!

Интересное название? То-то же! Оказывается, что есть и такой тип кода! Вы не представляете себе, до какой степени он может быть безопасным! Оказывается, чтобы от строки убрать три последних символа, нужно писать:
var
L:Integer;
S:String;
begin
L:=Length(S);
Inc(L,-3);
If L<0 then L:=0;
SetLength(S,L);
end;
Вместо более привычной строчки: If Length(S)>2 then Delete(S,Length(S)-2,3) else S:="";, т.к. первый вариант является безопасным, а второй нет! Почему? Я и сам не знаю! Вроде делают эти отрывки кода абсолютно одинаковую вещь! Единственное отличие этих отрывков кода, которое я нашел - это количество переменных и строчек кода! В безопасном варианте требуется лишняя переменная и 4 строчки программного кода, а в небезопасном ни одной лишней переменной и одна строчка программного кода!
Обо всем этом я узнал из разговора в чате с Anatoly Podgoretsky.
К чему это я все пишу? Ответ прост: Я хочу попросить объяснения, почему первый отрывок кода явяется безопасным, а второй - нет.
Собственно все!


 
VEG   (2002-08-10 23:59) [1]

Вот еще один безопасный код:
if Length(s)>2 then SetLength(s,Length(s)-3) else S:="";


 
TTCustomDelphiMaster   (2002-08-11 08:57) [2]

VEG © (10.08.02 23:18)
По моему все три кода являются безопасными, вот только код Anatoly Podgoretsky быстрее, меньше памяти занимает и менее понятный.

PS: Оптимизация if Length(s)>3 then SetLength(s,Length(s)-3) else S:="";


 
Anatoly Podgoretsky   (2002-08-11 10:02) [3]

VEG © (10.08.02 23:18)
Оба варианта безопасны, так как проводится проверка на допустимость, но ты передернул карты во втором случае. Ведь речь шла о коде Delete(S,Length(S)-2,3) без проверки If Length(S)>2
Вот такоей код не является безопасным.

Второе на что надо обратить внимания, хоть оба варианта и сделают желаемое, но Delete в первую предназначен для удаления символов изнутри строки, в то время как SetLength именно для изменения ее длины в большую и меньшую стороны.

В разговоре в чате, кроме того стояла речь об L:=Length(S)-3; вместо двух строк, как у тебя.

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


 
Anatoly Podgoretsky   (2002-08-11 10:26) [4]

TTCustomDelphiMaster © (11.08.02 08:57)
Это не мой код!
И с Delete не мой код!
Да и не в строчках я обычно считаю, а в операциях
Два присваивание, одно сравнение и один вызов процедуры.
Речь в чате зашла не об этом коде, а конкретно о коде VEG по работе с реестром, где на весь код ни одной проверки на допустимость, данный код был только демонстрацией принципа написания безопасных программ, так к слову, при том со ссылкой на ветку откуда это взято и на указание кто обратил внимание на потенциальную ошибку в Delete, это Дигитман, если делать это без проверок на допустимость значений.

Суть теории такова, зачем писать код с ошибками, что бы потом тратить время на отладку, лучше сразу писать код без ошибки.
Если есть параметры их надо проверять, если используются ресурсы, то их надо защищать с помощью try finally/try except блоков. Программа проверять не только на ограниченном наборе данных, но и на границных условия, на недопустимых данных.
В теории написания безопасного кода есть много различных приемов, даже следование части из них резко повышает надежность программ, меньше возможность, что в процессе эксплуатации, откуда то вылезет подлянка.


 
Юрий Зотов   (2002-08-11 10:32) [5]

> Оказывается, что есть и такой тип кода!

Совершенно верно, такой тип кода есть. Точнее, не тип кода, а стиль программирования. Вот простой, но наглядный пример:

Вариант 1:
with TMyObject.Create do
begin
...
Free
end;

Вариант 2:
with TMyObject.Create do
try
...
finally
Free
end;

Комментарии, думаю, не требуются. То же самое относится и к другим "парным" операциям (GetMem-FreeMem, BeginUpdate-EndUpdate, GetDC-ReleaseDC, SelectObject, OnChange:=nil - OnChange:=OnChangeHandler и т.д.).

Еще пример.

Вариант 1:
if CreateProcess(..., PI) then
begin
WaitForSingleObject(PI.hProcess, INFINITE);
GetExitCodeProcess(PI.hProcess, ...);
... // что-то делаем
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;

Вариант 2:
if CreateProcess(..., PI) then
begin
CloseHandle(PI.hThread);
WaitForSingleObject(PI.hProcess, INFINITE);
GetExitCodeProcess(PI.hProcess, ...);
CloseHandle(PI.hProcess);
... // что-то делаем
end;

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

Еще пример, уже на другую тему (увы, из собственной практики).

Вариант 1:
N := 0;
for i := 1 to Length(StringList.Text) do
if StringList.Text[i] = "A" then N := N + 1;

Вариант 2:
S := StringList.Text;
N := 0;
for i := 1 to Length(S) do
if S[i] = "A" then Inc(N);

Второй вариант кэширует свойство Text и использует Inc, а потому выполняется во много раз быстрее первого (в основном, за счет кэширования, конечно). Кстати, аналогичный прием в модуле VBA (кэширование свойств объектов - Workbook и пр.) как-то позволил ускорить работу макросов этого модуля в несколько десятков (!!!) раз (тоже реальный случай из практики).

Еще пример, с виду совершенно невинный.

procedure TMyCollection.Update(Item: TCollectionItem);
begin
... // что-то делаем
end;

Здесь нет вызова inherited. Вроде бы, он и не нужен - в классе-предке метод Update пустой, там только begin-end. Однако представьте, что в какой-то версии Delphi появились изменения и этот метод стал непустым. Все, большой привет - начиная с этого момента наш тщательно отлаженный и безукоризненно работавший код может начать глючить. И мы будем очень долго ломать голову над причиной такого странного явления. А если бы сразу написали inherited - не имели бы никаких проблем.

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

===== см. продолжение =====


 
Юрий Зотов   (2002-08-11 10:46) [6]

===== продолжение =====

Еще примерчик, в Вашего разрешения.

Вариант 1:
if <условие1> and <условие2> then...

Вариант 2:
if <условие1> then
if <условие2> then...

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

И подобных примеров "узких мест" можно привести очень много. Это практически все операции, явно или неявно связанные с выделением памяти и других ресурсов. Это скорость выполнения операций. Это оптимизация циклов (вынесение инвариантов и пр.), да и не только циклов (даже порядок следования ветвей в операторе case тоже имеет значение - желательно упорядочивать их по возрастанию параметра, так быстрее). Это пренебрежение особенностями машинной арифметики (особенно, с плавающей точкой). Это отключение проверок выхода за диапазон (хотя бы на этапе отладки программы). Это использование недокументированных возможностей или деталей внутренней реализации. Это закладка на умалчиваемые опции компилятора. Это и закладка на порядок следования модулей в uses (редкий, но очень тяжело локализуемый вид ошибок). Это пренебрежение хинтами и предупреждениями компилятора (лично сам видел, как человек забыл написать override в объявлении деструктора, а на сообщение компилятора наплевал - утечка памяти почти гарантирована).

Это... ну, в общем, это практически вся наша программа.

Конечно, абсолютно безопасного кода не существует в принципе, но в нашей власти сделать его более безопасным. Причем НАМНОГО более. Другое дело, что не следует становиться параноиком и втыкать проверки где надо и не надо.

Поэтому совет всем начинающим программистам - с самого начала старайтесь вырабатывать у себя именно грамотный, безопасный стиль. Он должен войти в привычку, стать просто стереотипом. И тогда Вы никогда не напишете begin вместо try (см. первый пример) - автопилот не позволит.

А как его вырабатывать? Очень просто - внимательность и аккуратность. Безопасный стиль, как это ни странно, начинается с самых простых вещей - форматирование текста, смысловые имена, соблюдение регистров и т.д. Ну и, само собой, надо думать буквально над каждой скобкой.

В общем, надо просто приучить себя к аккуратности. Без этого точно ничего не получится, а остальное придет с опытом.

Sorry за длинный постинг. Единственным его оправданием может служить то, что он, возможно, окажется кому-то полезным. :o)


 
Anatoly Podgoretsky   (2002-08-11 11:15) [7]

Спасибо Юрий Зотов, как всегда развернуто.
В чате речь зашла про конкретный код, строк 10 работы с реесром, аргумент был такой да все работает!
А к примеру с inherited он связан с тем недавним обсуждением, про удаление (усечение строки) на три символа с конца, там был аргумент про различные версии компилятора, что нельзя привязываться к внутренней реализации той или другой версии компилятра, проблемы неизбежны. Идя на встречу недобросовестным программистам Борланд изменил реализацию функции Delete теперь она работает следующим образом

If index is larger than the length of the S or less than 1, no characters are deleted.

В версиях 5 и ниже

If Index is larger than the length of S, no characters are deleted.

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


 
VEG   (2002-08-11 12:52) [8]

Все! Я разобрался!
Все дело в скорости!!!
Для проверки я использовал следующие отрывки кода:
Для первого безопасного:
var
L:Integer;
S:String;
Time:Integer;
FTD:Integer;
begin
Time:=GetTickCount;
For FTD:=1 to 1000000 do
begin
S:="ABC";
L:=Length(S);
Inc(L,-3);
If L<0 then L:=0;
SetLength(S,L);
end;
Time:=GetTickCount-Time;
Label1.Caption:=IntToStr(Time);


Для второго безопасного:
var
S:String;
Time:Integer;
FTD:Integer;
begin
Time:=GetTickCount;
For FTD:=1 to 1000000 do
begin
S:="ABC";
If Length(S)>2 then SetLength(S,Length(S)-3) else S:="";
end;
Time:=GetTickCount-Time;
Label1.Caption:=IntToStr(Time);


Для небезопасного:
var
S:String;
Time:Integer;
FTD:Integer;
begin
Time:=GetTickCount;
For FTD:=1 to 1000000 do
begin
S:="ABC";
If Length(S)>2 then Delete(S,Length(S)-2,3) else S:="";
end;
Time:=GetTickCount-Time;
Label1.Caption:=IntToStr(Time);

Оба безопасных варианта показали отличный результат! Первый безопасный справлялся в среднем за 110 мс., а второй - 124 мс.!!! Небезопасный вариант ОЧЕНЬ отстал от своих конкурентов. Его средний результат 890!!!
Для справок: Все тесты проводились на процессоре Pentium III - 550Mhz.
PS: Щас буду читать, что вы написали:-)


 
VEG   (2002-08-11 13:08) [9]

>Anatoly Podgoretsky
>Оба варианта безопасны, так как проводится проверка на допустимость, но ты передернул карты во втором случае. Ведь речь шла о коде Delete(S,Length(S)-2,3) без проверки If Length(S)>2
Вот такоей код не является безопасным.
А ты помнишь, как я тебе говорил, что к этому коду приплюсовать проверку нехватки количества символов? Это я и имел ввиду!
>Второе на что надо обратить внимания, хоть оба варианта и сделают желаемое, но Delete в первую предназначен для удаления символов изнутри строки, в то время как SetLength именно для изменения ее длины в большую и меньшую стороны.
Согласен!
>В разговоре в чате, кроме того стояла речь об L:=Length(S)-3; вместо двух строк, как у тебя.
Извини. В чате мы разговаривали утром, а текст я писал ночью. Копии разговора я не сохранил. Ошибся!
>Речь в чате зашла не об этом коде, а конкретно о коде VEG по работе с реестром, где на весь код ни одной проверки на допустимость, данный код был только демонстрацией принципа написания безопасных программ, так к слову, при том со ссылкой на ветку откуда это взято и на указание кто обратил внимание на потенциальную ошибку в Delete, это Дигитман, если делать это без проверок на допустимость значений.
Да. Было дело! Но! Во-первых - это не весь код, и этот код не демонстрирует мой стиль программирования. Ты говорил, что в том коде ошибок больше, чем строчек! Это НЕ так! Единственное, что там нужно сделать - это весь код поместить в try ... except!!! Но там ошибка может случиться 1/1000000 вариантов. Вот оригинал вопроса: http://delphi.mastak.ru/cgi-bin/forum.pl?look=1&id=1025549197&n=2
>Суть теории такова, зачем писать код с ошибками, что бы потом тратить время на отладку, лучше сразу писать код без ошибки.
Я высказал эту мысль чуток в другой форме: "Лучше заранее предохраниться от проблем!":-)

PS: Сейчас прочту текст "Юрия Зотова"


 
VEG   (2002-08-11 13:43) [10]

>Юрий Зотов
Спасибо за такое подробноя разъяснение! Что-то подобное не мешало бы опубликовать в разделе статьи.
>Другое дело, что не следует становиться параноиком и втыкать проверки где надо и не надо.
И это главное!

>Anatoly Podgoretsky
В игре у меня используется куча обработок ошибок. Реально произойти могут только 4 ошибки:
1. Видеокарта не поддерживает требуемый видеорежим.
2. Поврежденный вопросник.
3. Отсутствие всех файлов игры (кроме EXE-шника, естественною).
4. Отсутствие звуковой карты, или MPEG-3 Decoder-а.
В первом случае появится сообщение об несоответствии, потом ВСТРОЕННОЕ УСТРАНЕНИЕ НЕПОЛАДОК.
Во втором и третьем случаях программа ЗАПУСТИТСЯ безо всяких проблем и ошибок! Ведущий аккуратно объяснит проблему пользователю, и расскажет, как ее устранить!
В четвертом случае программа заблокирует звук. Если есть звуковая карта, то отправит на мой сайт за декодером.
Я люблю писать код аккуратно. То, что ты видишь в форумах - это те обрывки, которые еще малоисследованы мной. Они не иллюстрируют тот код, который написан в игре.
Я не знаю, что у тебя с IE, о только у тебя такие шрифты. Мой сайт не такой страшный. Другое дело - программа. Кроме Windows ей ничего не надо.Там все будет отображаться, как положено! А игра очень красивая! Она безопасна, и риск, об котором ты мне говорил, сводится к нулю!
Вообще, если честно, большинство программ в интернете написаны небезопасным кодом.


 
VEG   (2002-08-11 17:06) [11]

Интересно, а предложенный здесь ( http://delphi.mastak.com/cgi-bin/forum.pl?look=1&id=1027684797&n=7) мой код является безопасным?


 
Anatoly Podgoretsky   (2002-08-11 17:10) [12]

VEG © (11.08.02 17:06)
Нет, читай выше про парные команды, try/finally


 
Юрий Зотов   (2002-08-11 18:40) [13]

> VEG © (11.08.02 17:06)

Что ж, попробуем прокомментировать. Естественно, лишь с той точки зрения, как я сам это понимаю, не более того. И, чур, не обижаться, ОК? Расценивайте это, как дружескую критику - каковой она и является.

1. Оформление текста все же оставляет желать лучшего (регистр, отступы, пробелы). А безопасный стиль с него и начинается.

2. TBitmap.Create - а где try-finally? Представьте себе, что в момент вызова этой процедуры Panel1 или Image1 уже уничтожены (например, из-за ошибки в совсем другом месте) - и здравствуй, утечка памяти.

3. GetDC(0) - а где try-finally? Согласен, что на этом участке кода появление ошибки слишком маловероятно. Но если уж строго следовать канонам безопасности, то try-finally не помешает.

4. GetDC(0) - надежнее GetDC(GetDesktopWindow). Где гарантия, что в версии Win2005 нулевой хэндл по-прежнему будет означать десктоп, а не какой-то очередной наворот от дяди Билли?

5. PanelPoint:=ClientToScreen(Point(panel1.BoundsRect.Left,panel1.BoundsRect.Top));

Завтра Ваш коллега по проекту переложит Panel1 с формы на любой другой Parent (другую панель, TabSheet и т.д.) - и код заглючит. Надо привязываться к самой панели, а не к форме - например, можно использовать MapWindowPoints и точку (0,0).

6. ReleaseDC(0, ScreenDC) - см. п. 4.

7. Последнее - код далеко не оптимальный (лишние операции, лишние переменные, лишняя память).

Привожу свой вариант. Полагаю, что он проще, короче, понятнее и экономичнее (а все это тоже составляющие безопасности). Заметьте, что если где-то в другом месте программы была ошибка, то здесь она не маскируется, а, наоборот, проявится. Если же ее не было, то код сработает при любых перемещениях панели или нововведениях нашего любимого дяди Билли.


procedure TForm1.Button1Click(Sender: TObject);
var
PanelRect: TRect;
ScreenWnd: HWND;
ScreenDC: HDC;
begin
if GetWindowRect(Panel1.Handle, PanelRect) then // Неявная проверка Panel1
with Image1.Picture.Bitmap do // Неявная проверка Image1
begin
Width := Panel1.Width;
Height := Panel1.Height;
ScreenWnd := GetDesktopWindow; // Чтобы не вызывать дважды
ScreenDC := GetDC(ScreenWnd);
// Вот здесь try-finally уже лишнее - если ошибка есть,
// то она всплывет раньше.
BitBlt(Canvas.Handle, 0, 0, Width, Height, ScreenDC, PanelRect.Left, PanelRect.Top, SRCCOPY)
ReleaseDC(ScreenWnd, ScreenDC)
end
end;



 
VEG   (2002-08-11 20:36) [14]

>Anatoly Podgoretsky
>Юрий Зотов
Этот код я писал уже давновато. Можете сами ппроверить, поглядев на дату. Догда я еще ниразу не слышал понятия "Безопасный код"

>Юрий Зотов
За время программирования я приобрел СОБСТЕННЫЙ стиль программирования. Вот пример:
(******************************Название болка кода******************************)
Function Name(S:String):String;//То, что делает эта процедура; Описание переменных и т.д.
var
//Name :Type; //Comment
FTD :Integer; //Пример
STR :String; //Еще пример
const
XXX=0; //И еще пример:-)
begin
(*Название подблока*)
STR:="abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
+"abcabcabcabcabc";
If ... then
begin
For FTD:=1 to 100 do
begin
...
...
end;
end else ...;
If ... then ... else
begin
...
...
end;
If ... then
try
...
...
except
...
...
end
else
try
...
...
finally
...
...
end;
With ... do
begin
...
...
end;
For ... to ... do ...;
end;//Авторские права на процедуру, дата, время
Вас всех не должно волновать, что этот пример нерабочий! Это демонстрация моего стиля. Поймите! Мне так НАМНОГО удобнее! Код выглядит, как картинка!

Вот, например, так выглядит фрагмент с переменными у меня в игре:

(************************Параметры вопросных баз (Tags)************************)
BasePass :String; //Пароль доступа к вопроснику
BaseName :String; //Название вопросника
BaseNumAllQA :Integer; //Всего вопросов в вопроснике
BaseAutor :String; //Автор вопросника
BaseTopic :String; //Общая тема вопросника
BaseLoads :Integer; //Всего запусков базы

(**************************Работа с вопросными базами**************************)
BaseFName :String; //Имя файла вопросника
BaseFile :TextFile; //Файл вопросной базы
QA :array[1..15]of Integer; //Количетво вопросов
QABaseAll :array[1..15]of QABaseNum;//Все вопросы

(************************************Опции*************************************)
OnMusic :Boolean=True; //Музыка
OnTimer :Boolean=True; //Таймер
OnAnime :Boolean=False; //Анимация
MenuTimerSpeed :Integer=20; //Скорость таймера
для меню
Не код, а картинка!
Вот одна из процедур:
(******************************Системные поцедуры******************************)
procedure Delay(msecs : Longint);//Ждет msecs секунд, не зависая программу
var
FirstTick :longint; //TEMP для проверки времени
begin FirstTick:=GetTickCount;
repeat Application.ProcessMessages; {для того чтобы не "завесить" Windows}
until (GetTickCount-FirstTick >= msecs)or(GetKeyState(VK_SPACE) < 0);
end;


>Anatoly Podgoretsky


 
Oleg_Gashev   (2002-08-11 20:39) [15]

procedure Delay(msecs : Longint);//Ждет msecs секунд, не зависая программу
var
FirstTick :longint; //TEMP для проверки времени
begin FirstTick:=GetTickCount;
repeat Application.ProcessMessages; {для того чтобы не "завесить" Windows}
until (GetTickCount-FirstTick >= msecs)or(GetKeyState(VK_SPACE) < 0);
end;

А это зачем?


 
Oleg_Gashev   (2002-08-11 20:42) [16]

>Это демонстрация моего стиля.
> QA :array[1..15]of Integer; //Количетво вопросов
> QABaseAll :array[1..15]of QABaseNum;//Все вопросы

Плохой стиль. Будут проблеммы, если придется кол-во вопросов увеличить.


 
Oleg_Gashev   (2002-08-11 20:51) [17]

>BaseFName :String; //Имя файла вопросника
А если в имени файла больше 255 символов?


 
app   (2002-08-11 20:52) [18]

Не говоря о том, что она просто ошибочна, работает только при определенных условиях.
1. возврщаемое значение беззнаковое! DWord, а не знаковоый LongInt
2. в итоге даст ошибку при значении GetTickCount+msecs ~= 2^31, произойдет зацикливание или задержка в 24 дня, это относится к ранее упоминаемой проверки на работоспособность при предельных значениях.


Если хочешь иметь процедуру разогревающую процессор, то посмотри как это сделано в RxLib


 
VEG   (2002-08-11 22:21) [19]

>Oleg_Gashev
Количество вопросов по КАКТЕГОРИЯМ. Ты что, правил игры не знаешь??? В игре присутствует 15 вопросов. Правила игры менять не собираюсь! А в QABaseAll хранится динамический массив, который устанавливается автоватом по количеству вопросов. Количество вопросов ограничено типом Integer*15!!!
>А если в имени файла больше 255 символов?
Файл хранится в папочке QA вместе с игрой. В этой переменной хранится просто имя файла, без расширения и путя доступа!!! А имя файла, как известно, ограничено! Ошибка исключена!
>app
Во-первых максимально используемое в моей игре значение - это 10000!
Во-вторых здесь встроена возможность отмены всего процесса: GetKeyState(VK_SPACE) < 0!!!
В-третьих ЗАЧЕМ МНЕ ТРАТИТЬ ЛИШНЕЕ ВРЕМЯ НА ПРОВЕРКУ, И ЛИШНИЕ БАЙТЫ МОЕЙ ПРОГРАММЫ, если я точно знаю, какие значения я использую? Ведь пользователь не имеет право менять значения этих переменных!

ЗЫ Чтобы увидеть всю прелесть моего стиля написания кода, впишите его в редактор кода Delphi!!!
Примерный вид:
(******************************Название болка кода******************************)
Function Name(S:String):String;//То, что делает эта процедура; Описание переменных и т.д.
var
//Name :Type; //Comment
FTD :Integer; //Пример
STR :String; //Еще пример
const
XXX=0; //И еще пример:-)
begin
(*Название подблока*)
STR:="abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
+"abcabcabcabcabc";
If ... then
begin
For FTD:=1 to 100 do
begin
...
...
end;
end else ...;
If ... then ... else
begin
...
...
end;
If ... then
try
...
...
except
...
...
end
else
try
...
...
finally
...
...
end;
With ... do
begin
...
...
end;
For ... to ... do ...;
end;//Авторские права на процедуру, дата, время


 
Anatoly Podgoretsky   (2002-08-11 22:48) [20]

VEG © (11.08.02 22:21)
Слушай если хочешь говорить о своей игре это одно, а о стиле это другое, Олег справедливо заметил что это стиль плохой.
В таких случаях или объявляют или граничные константы или что еще лучше поддипазон, например:

type
QuestionsRange = 1..15; //Количество вопросов


QA : array[QuestionsRange]of Integer; //Количетво вопросов
QABaseAll: array[QuestionsRange]of QABaseNum;//Все вопросы

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


 
Юрий Зотов   (2002-08-11 22:52) [21]

> VEG © (11.08.02 20:36)

Выглядит красиво и читается очень хорошо, спора нет. Но ведь стиль только начинается с красоты, а вовсе не заканчивается на ней. Не буду повторяться насчет array[1..15] и беззнакового MSecs, а вот по поводу "разогревания процессора" добавлю к уже сказанному - подобные циклы задержки гораздо лучше делать на основе MsgWaitForMultipleObjects. Вот это действительно будет грамотный стиль - при минимальной загрузке процессора делается все, что нужно. Очень советую такую процедурку написать, она не раз пригодится.

Хотя и то что есть - уже неплохо. Некоторые профессиональные программисты пишут хуже. Увы...

P.S. Информация к размышлению.
Выражение msecs + FirstTick в Вашем цикле repeat является инвариантом. Никаких мыслей по этому поводу не возникает? Это ведь тоже стиль...


 
Anatoly Podgoretsky   (2002-08-11 23:03) [22]

Ну не знаю насчет красоты, но меня коробит код, в котором begin и предложение в одной строке, то же repeat


 
Юрий Зотов   (2002-08-11 23:11) [23]

> Anatoly Podgoretsky © (11.08.02 23:03)

Дело привычки, не более. Не стоит забывать, что парню всего 15 лет. Стиль оформления он еще не раз сменит и в конце концов все равно придет к стилю Borland, не он первый и не он последний. Не это главное - гораздо важнее стиль ПРОГРАММИРОВАНИЯ.


 
Oleg_Gashev   (2002-08-11 23:39) [24]

>Не это главное - гораздо важнее стиль ПРОГРАММИРОВАНИЯ.

Я извиняюсь. Это не более важно мышления программиста, его отношения к самому программированию. Я несколько раз затрагивал эту тему на форуме и в который раз все сводится к тому же. Нас учат программировать, но не учат мыслить. Мы пишем
QA :array[1..15]of Integer;
и не понимаем, к чему это может привести. Поэтому могу посоветовать VEGу изменить в первую очередь мышление, а стиль программирования уже выработается сам.


 
Юрий Зотов   (2002-08-11 23:59) [25]

> Oleg_Gashev © (11.08.02 23:39)

> в первую очередь мышление, а стиль программирования
> уже выработается сам.

Стиль программирования - "визуальное" отражение мышления программиста, его знаний и опыта. Эти вещи неразрывны, развиваются они всегда вместе. По сути, это одно и то же.


 
Torry   (2002-08-12 00:08) [26]

Юрию и Анатолию, в первую очередь:

Слушайте, я просто готов прямо сейчас сделать что-то типа раздела, где бы Вы оба разбирали бы примеры кода, на Торрике. Раньше былиа серия книг одного автора, фамилия начиналась на "К" - забыл уже, где это делалось. Жалко, что это - уже забытый способ давать информацию...

Давайте поговорим на эту тему в привате?


 
VEG   (2002-08-12 00:32) [27]

>Anatoly Podgoretsky
>Слушай если хочешь говорить о своей игре это одно, а о стиле это другое, Олег справедливо заметил что это стиль плохой.
Я привел свой стиль НАПИСАНИЯ кода! Ошибка сдесь исключена, т.к. в конкретном случае новый тип создавать лучше не надо!
>У меня за эти месяцы создалось впечатление, что тебе плевать на все советы.
Хе-хе... Какие месяцы? Об написании кода мы заговорили только вчера!
>Ну не знаю насчет красоты, но меня коробит код, в котором begin и предложение в одной строке, то же repeat
Сперва я изучал Delphi без книг и интернета, т.к. ни того, ни другого не было! Придумал свой стиль, и мне он очень нравится!
>Юрий Зотов
Эта процедура была создана еще в прошлом году! И я не знаю, что за MsgWaitForMultipleObjects ты имел ввиду.
>...что парню всего 15 лет.
Когда же вы все НАУЧИТЕСЬ считать! Мне 14!!!
>Oleg_Gashev
>и не понимаем, к чему это может привести.
А к чему это может привести?


 
Anatoly Podgoretsky   (2002-08-12 00:32) [28]

Трудно это делать на постоянной основе, для любых кодов, задача более подходящая для форумов, на примере привеленного кода или как серия статей, помню у Борланда тольли в Д2 толи в Д3 в документации с Дельфи было несколько глав Robust Application.

Дело тут не в коде, а в психологии человека, либо он готов писать код без ошибок либо нет, непосредственное общение весь благоприятствует этому.

Обычно комментарии по коду даются редко, мало кто готов к этому, просто в данном случае возникла специальная тема, выросла из обсуждения в чате.

Совсем другое дело Юрий - это в его натуре и он это делает профессионально.


 
Anatoly Podgoretsky   (2002-08-12 00:35) [29]

Конкретно для Д5
Developer’s Guide
Chapter 3
Common programming tasks


 
MrBeer   (2002-08-12 01:49) [30]

Юрий Зотов © (11.08.02 22:52)
Некоторые профессиональные программисты пишут хуже. Увы...


Profesional oznachaet tolko chto chelovek etim zarabativet sebe na hleb, t.e. eto neochem ne govorit...


 
FLIZ   (2002-08-12 01:55) [31]

я даже в 2 ночи ВСЕ прочитал что вы написали.
как хорошо что вы так прекрасно учите!
спасибо вам!


 
Юрий Зотов   (2002-08-12 01:56) [32]

> MrBeer © (12.08.02 01:49)

Это и имелось в виду. К большому сожалению.


 
VEG   (2002-08-12 02:05) [33]

Спасибо Юрию Зотову за все!
Всем пока! Ветка закрыта!
VEG умер. За это отдельное спасибо в первую очередь Anatoly Podgoretsky, а потом уже MrBeer и Oleg_Gashev!

>Anatoly Podgoretsky, MrBeer, Oleg_Gashev
И все-таки печально, господа, печально...


 
Юрий Зотов   (2002-08-12 02:19) [34]

> VEG © (12.08.02 02:05)

Зря. Зачем так болезненно реагировать? Подумай спокойно. Только не сейчас, завтра. Спокойно перечитай и спокойно подумай, ОК?


 
Anatoly Podgoretsky   (2002-08-12 09:24) [35]

VEG © (12.08.02 02:05)
Что бы так болезнено не реагировать, могу посоветовать, кроме совета Юрия об отдыхе, приводить для анализа не свой код, с явным указанием этого, проще тогда будет оценивать.


 
VEG   (2002-08-12 12:14) [36]

И что? Все уже повторяется уже несколько раз... Разве последние три дня предел? Нет конечно же! Будут еще и другие...


 
FLIZ_   (2002-08-12 12:18) [37]

2 VEG © (12.08.02 02:05)

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

"VEG умер"

с таким пафосом о себе говорят пожалуй тока индейцы
(типа "дохлый енот уходит от вас" :-) )
и ....женщины! :)

2 олл
а я вот почитал что умные люди пишут и у себя
в стиле огрехи нашел, и еще раз говорю этим людям -
спасибо что учите! информация - самая ценная вещь...


 
DenKop   (2002-08-12 15:52) [38]

IMHO:
Думаю к таким вещам как типы данных придираться не стиоит, если эти значения не доступны юзеру. Если программист знает, что его программа ни при каких условиях не сможет обратиться к элементу массива индекс которого >15, то он имеет полное право объявить свой массив как [1..15]. Но если всё же остаются вопросы, тогда нужно использовать только типы Extended или Cardinal, наверняка не промажешь. В таком случае возникает вопрос об экономии памяти, а это тоже будет критиковаться. Так что же получается, какой код ни предоставь, всё равно он будет не правильный, ведь так же: либо не экономный, либо вообще не правильный (т.к. вопросов может быть более 15-ти, хотя для разработчика - это одна из основных идей, что вопросов может быть не более 15).
В таком случае и для нужно предусмотреть случай, что вопрос может быть вообще отрицательный (например -12). ПАРАДОКС господа! И зря вы напали с такими грубыми критиками на праня. Ведь это стиль программирования, а не обязательное правило, например типа такого, как точка с запятой после каждой строчки.


 
VEG   (2002-08-12 15:59) [39]

>FLIZ_
Речь идет не об стиле. Об разговорах в чате последних трех дней.


 
Anatoly Podgoretsky   (2002-08-12 16:02) [40]

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


 
VEG   (2002-08-12 16:08) [41]

>DenKop
Согласен!
Спасибо за поддержку!


 
DenKop   (2002-08-12 16:45) [42]

Anatoly Podgoretsky >>
Думаю не стоит придираться к мелочам (я про ;), я выразился утрированно. Но всё же хочется услышать, что нибудь интересного по теме представленного парадокса. Я не думаю, что ВСЕМИ УВАЖАЕМЫЙ Anatoly Podgoretsky, зная, что его массив не может содержать более 15 эл-тов будет объявлять его как [1..1000](ничего не конкретизирую, пример опять же абстрактный!), т.к. его можно обвинить в иррациональности кода.
Но если же вы попытаетесь описать его как [1..15], то появится вопрос такого содержания: "А если вопросов более 15, что тогда, Access voilation, или Index out of bounds, или может, что ещё?!!" Вот в этом то и заключается главный парадокс в изложенных вами(и не только вами) мессагах и я вовсе собирался сводить критику к личным мотивам.


> Речь конечно не про его программу, до нее нет дела, речь
> не о стиле, хотя это часть концепции, речь о методике написания
> правильных программ, вот об этом и речь.

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

Говорить о том, что код QA :array[1..15]of Integer; не рацоинальный не имеет смысла не видя остальной части кода, где используетсяэтот массив. Ведь, возможно, он используется примерно вот так:

......
QA[3]:=23;
......
ShowMessage(IntToStr(QA));
......


Если это действительно так, то эту ветку можно считать вообще бессмысленным флеймом. Ведь так? Или я может в чём то не прав?


 
DenKop   (2002-08-12 16:48) [43]

Маленькая поправка ShowMessage(IntToStr(QA[3]));


 
Alx2   (2002-08-12 16:58) [44]

>DenKop © (12.08.02 16:48)
Это вы зря QA[3] написали. А где проверка
if 3 in [1..15] // вдруг под символом "3" замаскировалось другое значение?
then QA[3] := Variant(23) // А вдруг кто-то тип QA поменяет?
8)

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


 
Anatoly Podgoretsky   (2002-08-12 17:01) [45]

DenKop © (12.08.02 16:45)
Почему ветка весьма полезная.
Жалко что ее постоянно стараются отвести от темы в сторону личных программ и отношения.


 
DenKop   (2002-08-12 17:08) [46]

To Alx2>>

> вдруг под символом "3" замаскировалось другое значение?


Это я слышу в первый раз, а что собственно может замаскироваться под целочисленной константой?


> А вдруг кто-то тип QA поменяет?

Не совсем понял, кто может поменять тип и на каком этапе (User, Developer)? "А вдруг кто-то с помощью IDA игру переделает в какую нибудь систему программирования, например в какую нибудь Bear Pro или Elefant Pro (аналогия с Fox Pro)."


 
Юрий Зотов   (2002-08-12 17:48) [47]

Хотелось бы все же прекратить наши всегдашние разборки (странно, почему ну просто никогда без них не обходится?) и вернуться к теме. И не применительно к конкретному коду или программисту, а все же пошире.

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

В связи с этим мне хотелось бы узнать мнение всех программистов по примерно таким вопросам.

1. Нужен ли подобный раздел лично Вам?

Если да, то:

2. Каким Вы себе его представляете?
3. Что хотелось бы в нем ней видеть (какие подразделы и пр.)
4. Организация диалога с его ведущими (или не нужно вообще никакого диалога - просто статьи и все).
5. И т.п. - любые мысли на эту тему.


 
Игорь Шевченко   (2002-08-12 17:58) [48]

Юрий Зотов © (12.08.02 17:48)

У Тейксейры и Пачеко есть целая глава про стиль программирования, вроде, достаточно...

С уважением,


 
RV   (2002-08-12 18:01) [49]

Мне нужен
тоже форум, но с предмодерацией как на Королевстве Дельфи
да главное начать - далее на усмотрение ведущего


 
DenKop   (2002-08-12 18:18) [50]


> Хотелось бы все же прекратить наши всегдашние разборки (странно,
> почему ну просто никогда без них не обходится?) и вернуться
> к теме.

Согласен, просто очень часто, наши многоуважаемые мастера пытаются показать свой проффесионализм (или же обратное). Берёт зло и обида, т.к. обращение нащих профи с посетителями оставляет желать лучшего (пример VEG и не только, на моей памяти уже было три ветки такого рода). Ну да ладно, не будем о плохом.


> 1. Нужен ли подобный раздел лично Вам?

Думаю мне было бы очень интересно почитать, что угодно по этой теме, т.к. ничего подобного в сети не встречал.


> 3. Что хотелось бы в нем ней видеть (какие подразделы и пр.)

Думаю разделять на большое колличество подразделов не стоит. Думаю этого достаточно:
1. Общие принципы.
2. Правила красивого кода на API.
3. Скелеты безопасных конструкций. (думаю пояснений не нужно)


> 4. Организация диалога с его ведущими (или не нужно вообще
> никакого диалога - просто статьи и все).

Лично для меня набора статей было бы вполне достаточно.

Есть другой вопрос, где взять столько инфы и кто этим будет заниматься?


 
Romkin   (2002-08-12 18:20) [51]

2Юрий Зотов: Хотелось бы... А то после всех разговоров уже и думаю: вдруг неоптимально пишу?
2. Что-то вроде FAQ на этом сайте, возможно, как помесь со статьями (Новости раздела при входе)
3. Думаю, подразделы видны: Object Pascal, работа с WINAPI...
4. Не нужно диалога, форумы для этого есть. А вот форма для постинга своего кода на проверку должна быть. А после проверки ИМХО желательна возможность задать уточняющие вопросы проверившему (от автора постинга), и тд
5. И тп...


 
FLIZ_   (2002-08-12 18:24) [52]

мне нужен.
хочется :
1. увидеть образцы "эталлонного" безопасного кода по разной
тематике - работа с базами, с объектами, со стандартными
функциями ...
2. иметь возможность получить объяснения почему
он считается безопасным.
3. прислать свой код "на проверку", т.е. вынести его
прилюдно на обсуждение.

4. И ПЕРЕСТАТЬ в конце-концов РУГАТСЯ КАК ПОЛНЫЕ ...
давайте же черт возьми помнить зачем мы здесь, на форуме.
Лично я здесь УЧУСЬ!


 
Malder   (2002-08-12 18:46) [53]

Еще примерчик, в Вашего разрешения.

Вариант 1:
if <условие1> and <условие2> then...

Вариант 2:
if <условие1> then
if <условие2> then...

Вроде бы, одно и то же? Ан, нет


Можно, пожалуйста, пример, когда эти два кода будут выполнять НЕОДИНАКОВЫЕ действия.


 
Anatoly Podgoretsky   (2002-08-12 19:21) [54]

В настройках есть пункт Complete Boolean Eval и соответствующая директива ($BOOLEVAL), поведение первого кода будет зависить от их состояния, во втором случае нет, второе выражение будет выполняться только если выполнится первое, а для первого варианта всегда. Естественно результаты могут быть разные.
Такая подлая малозаметная ошибка.


 
MrBeer   (2002-08-12 19:23) [55]

To Malder:
skazali eto zavisit ot kompilyatora/opcii, t.k. ne yasno kotoraya chastj iz "if <условие1> and <условие2> then..." budet proveryatsja pervoi условие2 ili условие1. A kogda naprimer variant iz serii if (Something<>nil) and (Something.Size<>0) then... mozhet vizivatj access violation



 
vuk   (2002-08-12 19:28) [56]

to Malder:
>Можно, пожалуйста, пример, когда эти два кода будут выполнять
>НЕОДИНАКОВЫЕ действия.
Так там же все написано. Все зависит от того, какая схема вычисления булевых выражений используется.
Паример.

procedure SomeProc( DataSet : TDataSet );
begin
if (DataSet <> nil) and DataSet.Active then
begin
...
end;
end;

Предположим, что в эту процедуру передано значение nil.
1. Используется короткая схема вычисления. Производится вычисление первого условия. Оно не выполняется, поэтому можно заранее предсказать резкльтат всего логического выражения - это false. Поэтому второе условие не проверяется.

2. Используеется полное вычисление выражений. В этом случае выражения вычисляются полностью, поэтому, в отличие от первого случая, будет предпринята попытка получить значение свойства DataSet.Active. Но поскольку DataSet = nil, получим Access Violation.

Если же код переписать так
if (DataSet <> nil) then
if DataSet.Active then
...
То он будет работать правильно в любом случае.

Что же касается сложностей при групповой разработке и разных настроек компилятора на разных машинах, о которых упоминал Юрий Зотов, то это легко решается несколькими путями:

1. Административно. Нужно договориться об определенных настройках компилятора или утвердить их как внутренний стандарт.

2. Файл настроек параметров компилятора должен являться частью общего кода.

3. Настройки компилятора прописываются непосредственно в исходном коде. Как вариант - include. В этом случае всегда гарантируется правильная компиляция, т.к. опции, прописанные в исходниках имеют приоритет над установками компилятора в IDE.


 
Anatoly Podgoretsky   (2002-08-12 19:34) [57]

К тому же как обратил внимание MrBeer последовательность проверки может быть разной, так как проверяться должны оба условия, то не обязательно в этой последовательности.


 
Malder   (2002-08-12 19:39) [58]

Точно, точно. Торможу...


 
vuk   (2002-08-12 19:44) [59]

Я привел простейший случай... Естественно, что в сложных выражениях все будет еще более запущено. :o) Еще хуже будет, если в выражении будут использоваться функции, которые делают что-то необратимое и результат работы которых зависит от результата предыдущих проверок.


 
Anatoly Podgoretsky   (2002-08-12 19:49) [60]

Лучше использовать термин функционал - функция с побочными действиями, тут вообще только держись


 
Юрий Зотов   (2002-08-12 23:43) [61]

Уважаемые доны (как говаривал небезызвестный дон Румата), извините за назойливость, но все же убедительно прошу высказаться по поводу моего последнего постинга (не считая этого) :о)

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


 
Oleg_Gashev   (2002-08-12 23:54) [62]

> Юрий Зотов
Руками и ногами за. Давно пора.


 
Torry   (2002-08-13 00:08) [63]

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



 
Anatoly Podgoretsky   (2002-08-13 00:24) [64]

Дело за организацией, за формой


 
vuk   (2002-08-13 01:36) [65]

to Юрий Зотов:
По пунктам.
>1. Нужен ли подобный раздел лично Вам?
Видимо да. Учиться нужно всегда. А тут такая возможность поучиться на чужих ошибках, да еще (если вдруг) с разбором полетов. :o)

>2. Каким Вы себе его представляете?
С этим хуже. Это надо думать... Все, по большей части, зависит от того, кто будет этим заниматься.

>3. Что хотелось бы в нем ней видеть (какие подразделы и пр.)
Стандарты и стили оформления кода (об этом в этой ветке много говорили). Приемы безопасного/оптимального кодирования. Возможно методики локализации ошибок.

>4. Организация диалога с его ведущими (или не нужно вообще
>никакого диалога - просто статьи и все).
Зависит, опять же, от того, кто это будет организовывать и от его подхода к организации ресурса. Мне больше нравится подход, когда основой построения являются материалы и уже к ним привязаны обсуждения. Примерно так, как на Королевстве Delphi.

to Torry:
>и искренне извиняюсь перед Алексеем Вуколовым
Не стоит извинений.


 
blackweber   (2002-08-13 01:45) [66]

было бы очень хорошо


 
Виктор Щербаков   (2002-08-13 10:33) [67]

Юрий Зотов © (12.08.02 23:43)

1. Руками и ногами за. Такой раздел несомненно нужен.

2. Раздел должен дополнять форум, а не заменять его. В то же время он не должен быть статичным. Иначе станет нафиг никому не нужным. В связи с этим предлагаю следующие разделы:

3. а) статьи разных авторов.
б) регулярный разбор полетов (благо, материалов для этого в форуме предостаточно), которым бы занимались ведущие. Разделы по темам (Win API, OP, BD,...), ИМХО, не нужны.
в) как дополнение: борландовский стандарт кодирования на русском языке (то что у Тейксейры и Пачеко).
г) ...больше ничего в голову не приходит.

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


 
Сатир   (2002-08-15 14:44) [68]

2Юрий Зотов © (12.08.02 17:48)
было бы очень не плохо, если бы реализовалась Ваша идея, поскольку именно комментарии, имхо, куда больше дают возможность понять сам компилятор и его возможности, чем простой пример кода на тривиальный вопрос.
К тому же, такой подход и более продуктивен, поскольку будет представлять потенциал получения инфы о тонкостях самого программирования, что в свою очередь позволит более точно решать поставленные задачи.
с уважением, начинающий программист


 
kull   (2002-08-15 18:29) [69]

2 VEG

var
L:Integer;
S:String;
begin
L:=Length(S);
Inc(L,-3);
If L<0 then L:=0;
SetLength(S,L);
end;

Ненавижу if-ы.
То же самое в одной строкой и без условных операторов:

SetLength(S,Integer(Length(S)>2)*(Length(S)-3));

И не менее надежно...
(Помоему я уже писал про этот код тоже самое, но не помню где... )


 
DiamondShark   (2002-08-15 18:45) [70]


> kull © (15.08.02 18:29)


В отладчике на машкод посмотрите, и решите раз и навсегда: имеет ли смысл ломать мозги, а через два дня и глаза от такого кода.

Кстати, это же можно посоветовать и сторонникам "лаконичности" Ц++


 
Юрий Зотов   (2002-08-15 19:14) [71]

> kull © (15.08.02 18:29)

> И не менее надежно...

Абсолютно ненадежно. Отличный пример грубого нарушения принципов безопасного программирования - привязка к внутренней реализации.

В существующей версии компилятора False=0, True=1 и Ваш код работает. Однако, согласно официальной документации False=0, а True<>0. Поэтому, стоит завтра Borland"у решить, что удобнее, например, True=-1 - и Ваш код тут же перестал работать. А Borland не будет виновата - она осталась строго в рамках своей документации.


 
^Sanya   (2002-08-15 19:50) [72]


> 1. Нужен ли подобный раздел лично Вам?
Да, нужен. Я давно ищу чего-то подобного. К сожалению главы из классики (Тейксейер&Пачеко), на мой взгляд, недостаточно.
> Если да, то:
>
> 2. Каким Вы себе его представляете?
Зависит от того, сколько свободного времени наёдут Юрий Зотов и другие уважаемые мастера: если много, то хотелось бы увидеть возможность выставления+обсуждения своего кода
> 3. Что хотелось бы в нем ней видеть (какие подразделы и
> пр.)
вначале один раздел (вроде "общих вопросов"), а затем, если потребуется, выделять подразделы, и.е. от Общего к Частному по мере надобности,...постепенно. Если, к примеру, вопросов по WinAPI ставовится много, то создаёте подраздел по WinAPI.
> 4. Организация диалога с его ведущими (или не нужно вообще
> никакого диалога - просто статьи и все).
Да, хотелось бы.
> 5. И т.п. - любые мысли на эту тему.
Если реально, показывать народу свою программу с последующим обсуждением.(что-то вроде "Полигона" в Королевстве)



 
evgeg   (2002-08-15 20:17) [73]

В существующей версии компилятора False=0, True=1 и Ваш код работает. Однако, согласно официальной документации False=0, а True<>0.

The most common use of a Boolean expression is with relational operators and conditional statements. Since Boolean types are enumerated types, the following relationships apply:

False < True
Ord(False) = 0
Ord(True) = 1
Succ(False) = True
Pred(True) = False

Unlike Boolean variables, which can only assume the values 0 (False) or 1 (True) , ByteBool, WordBool, and LongBool can assume other ordinal values where 0 is False and any nonzero value is True.

Поставить Ord (..) вместо integer (..) -- и все будет абсолютно корректно. Хотя если судить по второму выделенному отрывку и integer (..) корректно.


 
evgeg   (2002-08-15 20:41) [74]

В общем то, если в лог. выражении может использовать не Boolean булевский тип, то integer лучше не ставить. Ord будет работать корректно всегда.


 
Anatoly Podgoretsky   (2002-08-15 20:49) [75]

Это типичный трюк


 
Jeer   (2002-08-15 21:16) [76]

>kull © (15.08.02 18:29)
>Ненавижу if-ы.
>То же самое в одной строкой и без условных операторов:
>SetLength(S,Integer(Length(S)>2)*(Length(S)-3));

Это - что-то.
Пример, как не надо писать, по крайней мере на Паскале.
И чего бы не вспомнить незабвенные времена:
Как это:
char far *(far *getint)(int far *);
высказать ?


 
Игорь Шевченко   (2002-08-16 11:13) [77]

Jeer © (15.08.02 21:16)

>char far *(far *getint)(int far *);

А что тот, собственно, непонятно ? И, главное, как это можно по-другому объявить ? :-)))


 
Виктор Щербаков   (2002-08-16 11:18) [78]


> char far *(far *getint)(int far *);

Когда я пытаюсь это сказать словами, получается с междометиями и без падежей :)))


 
Игорь Шевченко   (2002-08-16 11:28) [79]

Виктор Щербаков © (16.08.02 11:18)

Указатель на функцию, возвращающую указатель на строку символов, и принимающую параметром указатель на целое число.

Я про паскаль тоже много всего интересного могу наговорить, только вот надо ли ?


 
Jeer   (2002-08-16 11:29) [80]

Я и не сказал, что это плохая или неверная конструкция или есть короче запись или понятнее.
Ремарка была о том, что не надо вслепую переносить сишные приемы на паскаль.


 
kull   (2002-08-16 11:30) [81]


> Юрий Зотов © (15.08.02 19:14)

Прежде чем ссылаться на документацию, надо ее прочитать.
Передо мной лежит коробка с лицензионным Delphi, и в прилагаемой брошюре написано, что True соответствует 1, а False - 0.

Вот млин, заклинило тут многих с этой внутренней реализаций.
Нет у меня дурной привычки заглядывать, в исходники и копаться в asm коде. Я стараюсь отталкиваться только от документации и вам советую.


 
kull   (2002-08-16 11:33) [82]


> Jeer

А сишные приемы на Pascal я не переносил...
В C++ я все равно полный ламер. А кода по возможности должно быть меньше.
Проще конструкция - надежней код.


 
Anatoly Podgoretsky   (2002-08-16 11:40) [83]

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


 
Jeer   (2002-08-16 12:22) [84]

kull © (16.08.02 11:33)
>А кода по возможности должно быть меньше.

В общем-то да, конечно.
Но ЯВУ - это для чтения и написания человеком и безопасность кодирования впрямую связана с хорошей узнаваемостью и понимаемостью кода. А здесь без некоторых приемов их повышения не обойтись.

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


 
kull   (2002-08-16 12:23) [85]


> Anatoly Podgoretsky

Нет я не опираюсь на внутреннюю реализацию.

Вы возможно путаете понятия...

Для меня есть вход True, и выход 1;
Для меня есть вход False, и выход 0;
Все что происходит внутри этого черного ящика меня не волнует. Так вот то что происходит внутри это и есть внутренняя реализация. А когда я открываю Help и читаю, что должно быть на входе функции и что на выходе, то это не относится к внутренней реализации - это интерфейс, если угодно.

Кстати насчет внутренней реализации и копания в исходниках.-

Откройте любую версию Delphi и поищите в каталоге Delphi\Source текст - "Integer(".
Вы найдете в результатах поиска множество интерестных преобразований типа Boolean->Integer. Или Borland не следует своей документации?


 
kull   (2002-08-16 12:26) [86]


> Jeer © (16.08.02 12:22)

С этим а согласен. Конечно надописать проще и короче по возможности, но не в ущерб читаемости и надежности.


 
Виктор Щербаков   (2002-08-16 12:28) [87]


> Откройте любую версию Delphi и поищите в каталоге Delphi\Source
> текст - "Integer(".
> Вы найдете в результатах поиска множество интерестных преобразований
> типа Boolean->Integer. Или Borland не следует своей документации?

В этом случае привязки к текущей реализации нет. Преобразование быдет выполнять компилятор. Вернее он будет генерировать код для этого преобразования.


 
Anatoly Podgoretsky   (2002-08-16 12:32) [88]

kull © (16.08.02 12:23)
Я с тобой буду согласен, если мы будем говорить о конкретных реализациях Паскаля от Борланда, но если будем говорить о более широком спектре или более того вообще о методах написания безопасного кода, то я согласиться не смогу.

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

В тоже время в любом букваре по безопасному коду написано, избегайте преобразования или приведения кода без нужды.


 
VEG   (2002-08-16 12:41) [89]

Тестовая программа:
var
L:Integer;
S:String;
Time:Integer;
FTD:Integer;
begin
Time:=GetTickCount;
For FTD:=1 to 1000000 do
begin
S:="ABC";
(*Код для решения задачи*)
end;
Time:=GetTickCount-Time;
end;
Результаты тестов всех предложенных вариантов:
1.
L:=Length(S);
Inc(L,-3);
If L<0 then L:=0;
SetLength(S,L);
Результат: 110 мс.

2.
If Length(S)>2 then SetLength(S,Length(S)-3) else S:="";
Результат: 124 мс.

3.
SetLength(S,Integer(Length(S)>2)*(Length(S)-3));
Результат: 149 мс.

4.
If Length(S)>2 then Delete(S,Length(S)-2,3) else S:="";
Результат: 890 мс.

Для справок: Все тесты проводились на процессоре Pentium III - 550Mhz.


 
kull   (2002-08-16 12:50) [90]


> Виктор Щербаков
> В этом случае привязки к текущей реализации нет.

Что и требовалось доказать.
(Или может Boolean->Integer, будет компилится по разному в зависимости от того в каком каталоге находится?)


> но если будем говорить о более широком спектре или более
> того вообще о методах написания безопасного кода

В более широком спектре может не оказаться и функции SetLength...
Более того модет не оказаться длинных строк...


> Ссылка на код других программистов из Source хоть и хорошая,
> но не является доказательством...

А документация тоже не доказательство? Тогда какими "букварями" вы пользуетесь?



 
kull   (2002-08-16 13:12) [91]


> VEG © (16.08.02 12:41)

Естественно. В 1 случае Length вызывается только 1 раз а в других 2.

Но попробуйте строчку (S="ABC") сделать подлиннее, разница уже не столь велика.

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

Оптимизация нужна только тогда когда критична скорость работы.


 
DiamondShark   (2002-08-16 14:07) [92]

2 kull

Зачем такая глухая оборона? Из принципа?

Все понимают, что такой код не оправдан ни читабельностью, ни размером машкода, ни скоростью, ни надежностью.


 
kull   (2002-08-16 17:25) [93]


> Все понимают, что такой код не оправдан ни читабельностью,
> ни размером машкода, ни скоростью, ни надежностью.

Вы правы только в оценке скорости (и то может быть).


Если не нравится Boolean->Integer, вот вам другой код:

SetLength(S,Max(0,Length(S)-3));

Не менее надежно, читабельно, и по скорости сооветствует 1-ому варианту.
И я думаю это более читабельно чем:
L:=Length(S);
Inc(L,-3);
If L<0 then L:=0;
SetLength(S,L);


Так что я дмаю, что стремление к такому коду более оправдано.

Ну что теперь скажете насчет внутренней реализации?


 
VEG   (2002-08-16 20:25) [94]

Рейтинг изменился!
Для 1-го символа:
1.
If Length(S)>2 then SetLength(S,Length(S)-3) else S:="";
Результат: 89 мс., 910 мс.

2.
If Length(S)>2 then Delete(S,Length(S)-2,3) else S:="";
Результат: 90 мс., 910 мс.

3.
L:=Length(S);
Inc(L,-3);
If L<0 then L:=0;
SetLength(S,L);
Результат: 111 мс., 1140 мс.

4.
SetLength(S,Max(0,Length(S)-3));
Результат: 116 мс., 1275 мс.

5.
SetLength(S,Integer(Length(S)>2)*(Length(S)-3));
Результат: 145 мс., 1533 мс.


Для 3-х символов:
1.
L:=Length(S);
Inc(L,-3);
If L<0 then L:=0;
SetLength(S,L);
Результат: 110 мс., 1119 мс.

2.
If Length(S)>2 then SetLength(S,Length(S)-3) else S:="";
Результат: 124 мс., 1260 мс.

3.
SetLength(S,Max(0,Length(S)-3));
Результат: 125 мс., 1274 мс.

4.
SetLength(S,Integer(Length(S)>2)*(Length(S)-3));
Результат: 149 мс., 1516 мс.

5.
If Length(S)>2 then Delete(S,Length(S)-2,3) else S:="";
Результат: 890 мс., 8842 мс.


Для 6-ти символов:
1.
L:=Length(S);
Inc(L,-3);
If L<0 then L:=0;
SetLength(S,L);
Результат: 736 мс., 7413 мс.

2.
If Length(S)>2 then SetLength(S,Length(S)-3) else S:="";
Результат: 737 мс., 7442 мс.

3.
SetLength(S,Max(0,Length(S)-3));
Результат: 739 мс., 7473 мс.

4.
SetLength(S,Integer(Length(S)>2)*(Length(S)-3));
Результат: 758 мс., 7694 мс.

5.
If Length(S)>2 then Delete(S,Length(S)-2,3) else S:="";
Результат: 1172 мс., 11790 мс.


Время, потраченное на присваивание строки: 71 мс., 749 мс.

Примечание: Первая цифра - цикл 1000000; Вторая цифра - цикл 10000000.

Для справок: Все тесты проводились на процессоре Pentium III - 550Mhz.

Примечание от тестера: В первом тесте первые два победителя виграли как-бы не совсем честно, т.к. используют простое присваивание. Во-втором тесте три первых кода работали почти с одинаковой скоростью. Из всех тестов я получил вот такой код, на мой взгляд, самый оптимальный:
L:=Length(S);
If L>2 then SetLength(S,L-3) else S:="";

Вот то, что показали тесты:
Для 6-ти символов: 730 мс., 7407 мс.;
Для 3-х символов: 108 мс., 1126 мс.;
Для 1-го символа: 92 мс., 975 мс.;


 
kull   (2002-08-16 23:54) [95]

Да, первый вариант наиболее оптимальный, по скорости.

Разница между 7473 и 7413 - 0.8%, т.е. для часа в 3. варианте получаем 59 мин. 30 сек. в 1. варианте. Мощная оптимизация!

Но при длине строки S равной, например 100, разница в скорости совсем незначительна.


 
Anatoly Podgoretsky   (2002-08-17 00:06) [96]

kull © (16.08.02 17:25)
К такому коду вообще нет претензий


 
kull   (2002-08-17 00:16) [97]

Часто когда я слышу рассуждения и выкладки фанатов скорости, становится смешно.
Вообще-то о скорости надо заботится когда есть в это насущная необходимость.

У меня много горького опыта, основанного на стремлении нашего бывшего менеджера проекта к различной оптимизации:

Экономил он на каждой милисекунде, на каждом байте в трафике. Даже когда поля из Query вытакиваешь, он говорил что лучше вызывать не FieldByName(FieldName), а Fields[Index]. Мол так быстрее будет. Вместо Integer предпочитал byte - как же в 4 раза меньше места занимает! И прочие странные прихоти...

Так вот, наша команда до сих пор трахается над кодом, когда нужно изменить порядок полей в запросе, когда байта уже не хватает, или когда надо добавить новую функциональность. А менеджера этого нет в проекте уже 2 года, но "наоптимизировать" он успел много, по сию пору расхлебываем. Проект по его милости получился настолько негибким, нерасширяемым, и трудно сопровождаемым, что для себя мы поняли твердо - "Не надо заниматься преждевременной оптимизацией!"

Кстати о "букварях" по безопасному коду так там про оптимизацию тоже самое сказано.

Так что десять раз подумайте перед тем как размышлять о размере машкода и скорости.



Страницы: 1 2 3 вся ветка

Форум: "Потрепаться";
Текущий архив: 2002.09.12;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.81 MB
Время: 0.014 c
1-35660
Begin
2002-09-02 03:54
2002.09.12
Мне показалось, или на www.borland.com говорят о Delphi 7 ?


1-35655
supremum
2002-09-02 05:30
2002.09.12
MDI


3-35589
maxim2
2002-08-20 12:07
2002.09.12
Можно ли поместить ссылку или email в ячейку DBGrid


1-35715
$HiC0
2002-09-02 18:48
2002.09.12
Передача двумерного массива методу объекта...


1-35633
Strela
2002-08-30 01:18
2002.09.12
Динамическое создание объекта





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский