Delphi, Asm, C, WinAPI, PHP, ..., FAQ |
Добро пожаловать, гость ( Вход | Регистрация )
Delphi, Asm, C, WinAPI, PHP, ..., FAQ |
Siberian GRemlin |
Sep 18 2014, 09:26
Сообщение
#101
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
Кто подскажет как отловить что пишется.
Суть такая: после завершения программы на экран выводится сообщение «Except...», но выводится оно на доли секунды. Но проблема в том, что выводится оно после завершения приложения, т.е. после «end.». CODE Readln; end. И если запустить прогу с параметром, то в файле будет пусто либо то что выводим мы сами. CODE test.exe >err.txt Переписав всё в графическое приложение мы разумеется вообще ничего (сообщения об ошибке) не увидим. Как грамотный программист должен поступить в данном случае? Всё работает штатно, но это мелькание ошибки меня смущает. Есть подозрения, что шелудит «ActiveX». |
Axsis |
Sep 18 2014, 14:15
Сообщение
#102
|
Advanced Member Группа: CTPAX-X Сообщений: 121 Регистрация: 6-February 08 Пользователь №: 374 Спасибо сказали: 149 раз(а) |
Если не ошибаюсь, оператор перенаправления вывода ">" по-умолчанию перенаправляет только поток STDOUT, а ошибки выводятся в STDERR.
Попробуй так: CODE test.exe >>err.txt 2>&1 Это перенаправит STDERR в STDOUT, а его, в свою очередь, в файл err.txt Подробности: _ttp://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx?mfr=true Спасибо сказали:
|
-=CHE@TER=- |
Sep 20 2014, 22:53
Сообщение
#103
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Почитываю блог The Old New Thing, который ведёт Raymond Chen - один из программистов Microsoft. Блог интересный, оттуда можно много чего почерпнуть как из истории и архитектуры Windows, так и о том, как надо или не надо писать программы под эту систему.
Была там одна статья, код в которой ввёл меня в ступор (лишнее выкинул): CODE BOOL Is64BitWindows() { BOOL f64 = FALSE; return IsWow64Process(GetCurrentProcess(), &f64) && f64; } Код определяет, запущен ли процесс 32 на системе 64 (вызывать его в программе которая и так 64-битная смысла нет). Кстати, не забывайте, что IsWow64Process() есть не во всех Windows, так что LoadLibrary(Kernel32.dll) и GetProcAddress(IsWow64Process) вам в помощь. Так вот, меня поразило "&& f64" (&& - логическое And), ведь f64 до вызова было присвоено FALSE, а значит и вся конструкция "функция AND FALSE" будет равна FALSE. Однако же, потом до меня допёрло, что это верно только в случае когда выражение состоит только из констант (т.е. может быть посчитано компилятором на этапе компиляции), иначе выражения вычисляются слева на право. Т.к. сама функция IsWow64Process() может почему-то обламаться, то результат складывается во второй параметр (он передаётся по адресу). Таким образом, выполнение идёт следующим образом: сначала отработает IsWow64Process() и только потом её результат вычисляется совместно с f64 - т.е. на момент "&& f64", переменная "f64" уже изменена функцией. По той же причине будет работать и следующая конструкция: CODE char *s; <...> if (s != NULL) { if (s[0] == '?') { // todo code here } } при замене её на более короткую: CODE char *s; <...> if ((s != NULL) && (s[0] == '?')) { // todo code here } Приятная фича булевских вычислений в том, что если результат стал очевиден на любом этапе вычислений, то все последующие будут пропущены, так как результат от них уже не зависит. И хотя это для многих очевидно... Но! В математике от перестановки результат не меняется, так что конструкции "1 & 0" и "0 & 1" эквивалентны. Однако же в приведённых выше примерах при перестановке условий мы получим либо всегда FALSE в Is64BitWindows(), либо фатальную ошибку чтения памяти по адресу 0 когда s == NULL. Тут нужно заметить, что в Pascal и Delphi есть магический переключатель $B, который по умолчанию находится в выключенном состоянии, но если его включить, то все проверки будут выполняться полностью, что чревато в примерах выше неприятными последствиями (кроме кода, где проверки разделены на две вложенные). См. $B: Булева оценка в статье по ссылке. Попробуйте эту программу, а также её, но удалив "?" в коде: CODE {$APPTYPE CONSOLE} var p:pchar; begin p:=nil; {?$B+} writeln((p <> nil) and (p^ = #10)); end. Но, возвращаясь к упомянутому блогу, ещё одна занимательная статья, про которую хочется сказать: Non-classical processor behavior: How doing something can be faster than not doing it Название можно перевести как "когда делать что-то может быть быстрее, чем не делать этого". Разгадка проста |
-=CHE@TER=- |
Sep 23 2014, 14:23
Сообщение
#104
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Кто работает с PHP наверное знает, что в php.ini нужно обязательно указать часовой пояс, иначе функции работы с датами будут, во-первых, работать неверно, а, во-вторых, вываливать Warning'и.
Устанавливается часовой пояс так (для Москвы): CODE [Date] ; Defines the default timezone used by the date functions ; http://php.net/date.timezone date.timezone = Europe/Moscow Недавно заметил, что у меня разница в 1 час выводимого времени с тем, что должно быть. Из-за того что в России отменили переход на зимнее/летнее время (кстати, 26 октября 2014 опять стрелки крутить будем), а в PHP, видимо, это где-то жёстко зашито, то пришлось искать способ явно указывать часовой пояс, без сохранения летнего времени. Так вот, указывать нужно вот так (для Москвы): CODE date.timezone = Etc/GMT-4 У кого-то сейчас может начать трещать шаблон почему вместо "+4" стоит "-4", однако же это такая особенность (выделение моё): QUOTE If you disregard the above warning, please also note that the IANA timezone database that provides PHP's timezone support uses POSIX style signs, which results in the Etc/GMT+n and Etc/GMT-n time zones being reversed from common usage. © PHP Manual: Other time zonesFor example, the time zone 8 hours ahead of GMT that is used in China and Western Australia (among other places) is actually Etc/GMT-8 in this database, not Etc/GMT+8 as you would normally expect. |
Siberian GRemlin |
Sep 23 2014, 14:48
Сообщение
#105
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
Кто мне подскажет когда и как правильно использовать CoUninitialize? Пишут, что нужно в каждом потоке делать CoInitialize(nil) и CoUninitialize. А что если у меня создаётся поток, в нём проверяется возможно ли подключиться к БД чрез ADO, а в главном потоке нужно либо переходить к работе с БД или завершать работу приложения. Придумал не я, этого требует задание. Дак вот если подгрузка делается в отдельном потоке и никак иначе, то когда делать выгрузку в данном случае?
|
-=CHE@TER=- |
Sep 23 2014, 17:35
Сообщение
#106
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Можно одним вызовом со специальным параметром разрешить для всех потоков процесса:
QUOTE Did you get that? If any thread in the process calls CoInitialize[Ex] with the COINIT_MULTITHREADED flag, then that not only initializes the current thread as a member of the multi-threaded apartment, but it also says, "Any thread which has never called CoInitialize[Ex] is also part of the multi-threaded apartment." © Why does CoCreateInstance work even though my thread never called CoInitialize? The curse of the implicit MTAИ ещё пара полезных ссылок о подводных камнях: для C++ и для Delphi. Спасибо сказали:
|
Siberian GRemlin |
Oct 24 2014, 06:21
Сообщение
#107
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
Как я понял, во всех 64-разрядных «Окнах» обращения 32-разрядных программ к реестру перенаправляется. Из
CODE HKEY_LOCAL_MACHINE\SOFTWARE\ вCODE HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ Долго понять не мог почему игра не подхватывает свои параметры, пока не сделал проверку обращений к реестру. «Google» подтвердил.Спасибо сказали:
|
-=CHE@TER=- |
Oct 24 2014, 17:54
Сообщение
#108
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Там не только реестр - там, вообще, очень хитрое колдунство: MSDN: Running 32-bit Applications.
См. ссылки в "In this Section" - там по каждой грабле отдельная статья, объясняющая чем она грозит. Если ты делаешь установщик и он 32-битный, то проблем не должно быть. А вот если ты файл реестра просто экспортируешь... я не уверен, но попробуй там, в начале, написать "REGEDIT4" вместо "Windows Registry Editor Version 5.00" (или что оно там на современных системах добавляет) - может RegEdit догадается что файл старый и его нужно в ветку 32 пихать. |
Axsis |
Oct 26 2014, 23:48
Сообщение
#109
|
Advanced Member Группа: CTPAX-X Сообщений: 121 Регистрация: 6-February 08 Пользователь №: 374 Спасибо сказали: 149 раз(а) |
RegEdit'а тоже две версии. Из 32-битных приложений вызывается один и пишет в виртуальные ветки, из 64-битных вызывается другой.
Я однажды долго не мог понять почему .reg файл, импортируемый из тотал командера (32-битного) не показывается в реестре, и в программе (x64) не работают настройки, которые я импортирую. А потом обнаружил, что regedit, вызванный из тотала и regedit, вызванный через "пуск->выполнить" показывают разный реестр... (в первом случае 32-ух, а во втором - 64-бинтую его версию). Добавил тот же самый .reg файл в реестр из проводника и всё заработало как и должно было. PS: а "REGEDIT4" вместо "Windows Registry Editor Version 5.00" писать бесполезно в данном случае... Спасибо сказали:
|
Siberian GRemlin |
Oct 28 2014, 10:02
Сообщение
#110
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
Искал как проверить наличие связи с интернетом, нашёл статью. Из рассмотренных в ней вариантов достоверным оказался только последний. Проблема в том, что после такой проверки перестаёт работать «Synapse» — на все запросы приходит ответ с кодом 500. Отключаю проверку связи и всё отлично. Кто-нибудь сталкивался или может знает другие способы проверки связи?
|
-=CHE@TER=- |
Oct 28 2014, 12:47
Сообщение
#111
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
WSACleanup() убери оттуда.
Как я понял, твой Synapse с сокетами работает, а вызов этой подпрограммы нахрен закрывает библиотеку WinSock. И, кстати, я там не увидел, чтобы они где-то в коде WSAStartup() делали, чтобы библиотеку закрывать. |
-=CHE@TER=- |
Nov 29 2014, 14:51
Сообщение
#112
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Немного интересной и полезной информации по .BAT файлам.
1) Недавно перечитывая справку по .BAT файлам в Windows, натолкнулся на такую штуку: CODE @echo off if _%1 == _ goto quit program.exe %1 :quit Оказывается в Windows (в 98-ой не проверял, но в XP точно есть) можно сделать проще (справка по "goto /?"): QUOTE Изменение команды GOTO при включении расширенной обработки команд: Таким образом, скрипт можно сократить:Команда GOTO принимает в качестве метки перехода строку :EOF, которая вызывае передачу управления в конец текущего пакетного файла. Это позволяет легко выйти из пакетного файла без определения каких-либо меток. Команда CALL /? выводит описание расширенных возможностей команды CALL, делающих эту функцию особенно полезной. CODE @echo off if _%1 == _ goto :EOF program.exe %1 Для тех, кто не в курсе - если вместо "goto <конец_файла>" делать exit, то это прекращает выполнение вообще. К примеру, если из одного .BAT файла через call вызвали другой, то при exit произойдёт выход из обоих файлов, а не возврат в верхний. 2) А ещё команду call можно вызывать с метками и параметрами - см. справку по "call /?". 3) Но и это ещё не всё. Перечитывая FAQ к DOS Navigator 1.51 (C:\DN\DOC\DN-FAQ25.TXT) я нашёл там такое: QUOTE Q > Зачем в DN.HGL сделано 'comentstring ::' в .BAT-файлах". A > Потому, что набоp '::' в начале стpоки аналогичен REM, более того, это даже более гpамотно, так как REM все же команда DOS и вся стpока пеpедается командному пpоцессоpу на обpаботку, а ':' это не команда, а метка (что, видимо, и так все знают), а вот если после ':' стоит символ, котоpый не может быть частью названия метки (точнее метка, котоpой нет), то DOS пpосто пpопускает эту стpоку, т.е. получается тот же комментаpий, только экономится запуск целой команды. Для командных файлов с многими REM'ами можно добиться некотоpого ускоpения запуска. А '::' - уже установившийся de-facto стандаpт, кpоме того так пpоще набиpать и так гоpаздо кpасивее. Не знаю, насколько эта фича документированна, но такая штука: CODE @echo off Вполне себе работает.rem комментарий :: это тоже комментарий echo тест P.S. Годная, хотя и старая, книжка Стивен Симрин. Библия MS-DOS (версии 3.30), особенно там интересны всякие описания по физическому устройству дисков и файловой системы. Чего я про неё пишу - там описывается, что до MS-DOS 3.30 не было команды call и прямой вызов одного .BAT файла из другого приводил к невозможности возврата, поэтому приходилось выкручиваться. Спасибо сказали:
|
-=CHE@TER=- |
Dec 7 2014, 17:20
Сообщение
#113
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
С некоторого времени трахаюсь (простите за мой французский) с WordPress.
Куча какого-то хренового кода, старого как экскременты мамонта, который никто не хочет исправлять и/или удалять (см. обсуждения по ссылкам). То, что основательно выжрало мне время: 1) Все значения в $_POST и $_GET экранируются через addslashes(), независимо от настройки get_magic_quotes_gpc() (которая уже давно протухла и не поддерживается). Сделано это для подтирания соплей криворукожопым дебилам пишущим что-то типа: CODE $result = $wpdb->get_results('SELECT * FROM users WHERE name='.$_POST['name']); забы(и)вающим про(на) mysql_real_escape_string() и подобные функции, чтобы исключить SQL-инъекцию. Подробнее: раз и два. Так что будьте готовы делать stripslashes(), если вам нужна оригинальная строка. 2) Вторая вещь, с которой вы будет как минимум полчаса сношаться не понимая что к чему - это высота <select> при свойстве multiple (множественный выбор). Она не меняется. Чтобы поменялась нужно в файле со стилями указать (auto - чтобы свойство size работало, указывающее сколько строк должно быть видно): CODE #wpcontent select[multiple] { height: auto; } Когда вы допрёте до этого, то наверняка узнаете что разработчики пару лет как в курсе, но им глубоко пофигу на ваши проблемы и потраченное время. 3) Не WP, но рядом - плагин AutoComplete для jQuery (jQuery Autocomplete plugin 1.2.2). Вызываем так - всё работает: CODE jQuery('input[name="city"]').autocomplete('cityfind.php', { selectFirst: true, // выбирать первый найденный minChars: 4 // как минимум 4 символа должны быть введены }); Всё отлично и зашибись. Теперь, чтобы не гонять зря запросы на сервер, делаем локальный массив (citylist) и выгружаем все нужные города туда: CODE // короткий пример списка // на деле там 3K городов // в отдельном файле citylist.js var citylist = [ "Detroit", "Los Angeles", "New York" ]; <...> jQuery('input[name="city"]').autocomplete(citylist, { selectFirst: true, minChars: 4 }); И оно нихрена не работает! Мне пришлось дебажить этот плагин прямо по шагам, залезая в каждый метод, чтобы, в итоге таки найти что нужно обязательно добавить свойство: CODE matchContains: true, чтобы эта херня заработала (вставить сюда тонны ненависти)! Потому что: CODE function request(term, success, failure) { if (!options.matchCase) term = term.toLowerCase(); // term - введённая строка в нижнем регистре var data = cache.load(term); if (data) { <...> // нам нужно сюда! } } // смотрим cache.load(): function load(q) { // здесь всё нормально if (!options.cacheLength || !length) return null; // options.url == null (т.к. мы массив передали) // но options.matchContains == false (по умолчанию)! if (!options.url && options.matchContains) { <...> // нам нужно сюда! } return(null); } И гугление в Интернете вам не поможет - я там даже упоминания об этом не нашёл! |
Siberian GRemlin |
Apr 1 2015, 13:11
Сообщение
#114
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
У кого-нибудь есть идеи как быстро читать строки из текстового файла размером боле 1 гига (более 90,5 миллионов строк)?
Чтение строками (предполагалось, что там все строки равной длины) заняло 1,5 часа, это при том, что я весь файл загрузил в память. Но оказалось, что в них есть ошибки и длина части строк разнится. Не представляю сколько уйдёт времени на чтение посимвольно. Есть мысль загружать часть файла в память и оттуда читать в какой-нибудь TStringList. Интересно, будет ли быстрее. P. S. Отвечу на возможный вопрос. Это выгрузка БД в CSV, нужно сравнить свои значения со всеми значениями в ней. |
-=CHE@TER=- |
Apr 2 2015, 11:31
Сообщение
#115
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Конкретизируй задачу (опиши коротко и понятно на каком-нибудь похожем примере).
Потому что если тебе просто нужно сравнить свои значения с теми что там, то всю БД в память загружать и не нужно - прочитал одну строку, распарсил, нашёл нужные занчения, сравнил, затем прочитал следующую и так далее. При таком подходе тебе нафиг грузить файл в память не упёрлось, что быстрее и проще. Я бы читал файл блоками: 1) Скажем, известна максимальная длинна строки - пусть будет 500 символов. 2) Читал бы с запасом блок в 512 символов. 3) Парсил бы его и искал конец строки. Скажем, строка бы была длинной в 302 символа. 4) На этом шаге парсил строку и вытаскивал нужные значения. 5) Здесь перемещал бы оставшийся блок в 512-302=210 символов в начало буфера, затем читал бы из файла остаток в 302 байта и переходил бы к пункту 1. Если сделать буфер кольцевой, то даже перемещать ничего не нужно - будет быстрее, но с реализацией замороченнее. К слову сказать, пункты 2-5 умеет делать буферизованный ввод/вывод Сишных функций fgets() - читает строку из файла. В Delphi можно подключить через external библиотеку msvcrt.dll и оттуда эту функцию тягать (ещё fopen() и fclose() понадобятся). Если же тебе нужно постоянно что-то там сравнивать, то проще и быстрее будет загрузить твой .CSV обратно в какую-нибудь БД и уже с БД и работать. Вот, держи, можешь замерить скорость - по идее, должно быть быстро. Учти только, что fgets() возвращает строку с символом перевода на конце (если это не последняя строка в файле) и строки там ASCIIZ (с нулём на конце). CODE program functest; {$APPTYPE CONSOLE} function fopen(filename: pchar; filemode: pchar): pointer; cdecl; external 'msvcrt.dll'; function fgets(s: pchar; n: integer; fptr: pointer): pchar; cdecl; external 'msvcrt.dll'; function fclose(fptr: pointer): integer; cdecl; external 'msvcrt.dll'; var f: pointer; s: array[0..1023] of char; begin // open for (r)ead as (t)ext file = rt f:=fopen('functest.dpr', 'rt'); // file open ok if (f <> nil) then begin // first line fgets(s, 1024, f); writeln(s); // second line fgets(s, 1024, f); writeln(s); // close file fclose(f); end; end. Спасибо сказали:
|
Siberian GRemlin |
Apr 3 2015, 10:35
Сообщение
#116
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
Да, до меня до самого допёрло, что всё сразу в памяти держать не нужно.
Но я немножко по другому сделал. По 10-100 метров (пока не решил сколько лучше брать) гружу, догружаю до конца строки и загоняю в TStringList, и массив сам заполняется, причём достаточно быстро. После сравнения выгружаю и читаю следующий блок. Как оказалось, длина строки меняется из-за косяка в кодировке: кириллица осталась в юникоде, когда всё остальное — в ANSI. Сообщил об этом, а они сообразить не могут, что я от них хочу. Можно было сделать это всё через, например, SQL, но заказчик не осилит его использование. |
-=CHE@TER=- |
Apr 3 2015, 15:30
Сообщение
#117
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Можно было сделать это всё через, например, SQL, но заказчик не осилит его использование. Тогда, как вариант, можно программу сделать, в которую вводишь сервер, порт, логин, пароль и имя базы данных, а она уже сама нужные запросы делает и выводит статистику. |
Siberian GRemlin |
Apr 6 2015, 09:48
Сообщение
#118
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
Доступа нет к серверу и не будет. Есть только выгрузка.
|
-=CHE@TER=- |
Jul 8 2015, 15:40
Сообщение
#119
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Переписывал на сях пару дней назад bnkextr, а также wav2ogg, причём в последней программе нужно было делить размеры блоков на 255. Если помните, то в OggS размер блока записывается как байт N, а затем N байтов сумма которых даёт полный размер блока.
И тут я вспомнил подсмотренный (уже не помню где) прикольный способ подсчёта. В общем, если нам нужно разделить блок данных размером datasize байт на пакеты по packsize байт, то, обычно, делают как-то так ("/" = "div"; "%" = "mod" в Pascal/Delphi): CODE packets = datasize / packsize; if (datasize % packsize) { packets++; } Собственно проверка нам нужна когда остаётся остаток от деления - т.е. какой-то пакет (обычно последний) будет неполный. Занимает всё это безобразие аж 4 строчки и смотрится уродско. А можно записать в одну и красиво: CODE packets = (datasize + (packsize - 1)) / packsize; Если кто не понял что тут делается, то задам вопрос: когда у нас появляется остаток? Когда datasize целиком не делится на packsize. Рассмотрим на примере: пусть packsize = 5. Тогда остаток в datasize может быть 1, 2, 3 или 4. Если теперь увеличить datasize на packsize - 1 (т.е. на 5 - 1 = 4), то любое из этих чисел даст число большее, либо равное packsize, но (это важно!) всегда будет меньше packsize * 2 - т.е. при делении на packsize мы получим тот самый дополнительный пакет, причём он будет ровно один. Способ красив, но не лишён недостатков, а именно переполнения (когда сумма делимого вылезает за размеры базового типа), так что использовать его следует в тех случаях, когда гарантировано сложение переполнения дать не может. У варианта выше с двумя делениями такого недостатка нет, так что имейте это ввиду. |
-=CHE@TER=- |
Aug 24 2015, 22:08
Сообщение
#120
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
В последнее время больше пишу на сях, чем на Pascal/Delphi.
Когда-то, помню, тратил кучу времени на перевод примеров или кода с C/C++ (так как большинство всего этого было именно на упомянутых языках) на Pascal/Delphi. Дело в том, что си позволяет сделать много, коротко и просто. Чего Delphi/Pascal не может. Давайте рассмотрим примеры. Есть некий буфер в памяти который надо как-то изменить для дальнейшего использования. Скажем, нужно занулить первый байт. Pascal: CODE Var p: ^Byte; { PByte } ... p^:=0; C: CODE BYTE *p; ... *p = 0; /* или p[0] = 0; */ Теперь усложним пример - нам нужно также занулить 4 и 8 байты. C: CODE /* от нуля, так что 4-1 и 8-1 */ p[0] = 0; p[3] = 0; p[7] = 0; А вот с Pascal начинается геморрой: CODE p^:=0; inc(p, 3); p^:=0; { 7-3 = 4 } inc(p, 4); p^:=0; { вернули назад, иначе при освобождении памяти отхватим ошибку! } dec(p, 7); Можно, конечно, попытаться извернуться со своим типом-массивом: CODE Type TList = Array[0..0] Of Byte; PList = ^TList; ... Var p: ^Byte; l: plist; ... l:=Pointer(p); l[0]:=0; { а тут нас ждёт "Error: Constant expression violates subrange bounds", ибо массив был от 0 до 0, поэтому придётся заводить переменную типа integer, скажем n, и писать n:=3; l[n]:=0; - тогда будет работать } l[3]:=0; Видите, сколько лишнего кода приходится писать? Конечно, можно объявить нашу перменную как Array of Byte, но большинство библиотек и программ работают именно с обычными указателями. Можно ещё все извращения с inc()/dec() обернуть в функцию. Можно ещё много чего. А можно писать на сях, что удобнее, быстрее, короче и проще. Я уж не говорю про #define'ы - эта вещь, вообще, помогает сократить код и выкинуть всё лишнее. А ещё есть "?". Просто посмотрите: C: CODE #define MY_MAX(a,b) (((a) > (b)) ? (a) : (b)) ... m = MY_MAX(x,y); /* заменить значение 123 на 0, а иначе оставить как есть */ m = (m == 123) ? 0 : m; Pascal: CODE { здесь для той же операции придётся создавать функцию; более того - если нужно будет сравнить два значения другого типа (не integer), то придётся делать ещё одну, отдельную функцию на каждый такой тип данных! т.к. #define в сях это макрос, то он таких недостатков лишён } function my_max(a, b: integer); begin if (a > b) then result:=a else result:=b; end; ... m:=my_max(x,y); { здесь только полностью писать if() } if (m = 123) then m:=0; Или, вот, скажем, в сях любое условие считается ложным, только если оно ноль/NULL - иначе истина. C: CODE BYTE *p; int i; bool b; ... p = malloc(10); /* если p не NULL; Pascal: if (p <> nil) then ... */ if (p) { ... free(p); } /* если b - истина (false = 0); Pascal: if b then ... режим {$X+} в Pascal должен быть включён, иначе нужно будет писать полностью if (b = True) then ... */ if (b) { ... } /* если i что угодно, но не ноль; можно также записать как if (i != 0) { ... } Pascal: if (i <> 0) then ... */ if (i) { ... } /* если i ноль (!i - "не i"); можно также записать как if (i == 0) { ... } Pascal: if (i = 0) then ... */ if (!i) { ... } В общем, код сокращается от лишних и ненужных операций, становится проще и понятней для чтения, а главное делать теперь это не в пример быстрей. При написании же кода также тратится куда меньше сил и времени. Pascal/Delphi хорош для изучения языка и начинающих программистов - он приучает к порядку и аккуратности. Но потом многие из особенностей языка начинают откровенно мешать. И вот тогда, в сравнении, приходит осознание насколько же си крут. Конечно, там нет строк (в смысле, они есть, но ASCIIZ, так что будет много головняка с выделением памяти, склейкой и прочей фигнёй, которая может привести к buffer overflow если не доглядеть; вообще говоря, в C++ есть класс CString (си строчки) и прочие такие костыли), а .DLL файлы, если загружаются не динамически через LoadLibrary(), а статически, то подключаются через адовый геморрой посредством .DEF файлов (в Delphi же это делается одной строчкой...), и ещё много чего, так что будьте готовы к тому, что то что за вас раньше делал компилятор, теперь придётся делать самостоятельно, но язык того стоит. Так что если у кого-то будут вопросы по языку - задавайте, могу помочь разобраться. |
Упрощённая версия | Сейчас: 6th November 2024 - 18:44 |