мой стиль... Копирайтов не держу и честно признаю что он в немалом навеян стилем Торвальдса: static char *next_line (char *line, char ch, char *text) { while (text[0] == '\x0a' || text[0] == '\x0d') text ++; /* проверка на '\0' тут не нужна случайно? */ if (text[0] != ch) return NULL; while (text[0] != '\x0a' && text[0] != '\x0d') (line++)[0] = (text++)[0]; line[0] = '\0'; return text; } static char *first_line (char *line, char ch, char *text) { while (1) { /* условия можно было бы и не переставлять, * но мне не нравиться конструкция text[-1] */ if (text[0] == '\x0a' || text[0] == '\x0d') if (ch == text[1]) return next_line (line, from); text ++; } } void Fill_List(int buttonID) { char buffer[256]; char* lpText; char ch; GetDlgItemText (hWnd, buttonID, buffer, 256); cr_strlcase (buffer); // перевод caption в нижний регистр ch = buffer[0]; lpText = ch < 0 ? lpRus : lpEng; /* так просто короче */ SendMessage (hList, LB_RESETCONTENT, 0, 0); for (lpText = first_line (buffer, ch, &lpText[2]); lpText != NULL; lpText = next_line (buffet, ch, lpText)) { SendMessage (hList, LB_ADDSTRING, 0, (LPARAM)buffer); } } [add] блин извиняйте, забыл табуляции заменить пробелами .
cresta > "Строки разделены последовательностью 0D0A" В таком случае не обязательно в while использовать двойное условие Обычно при сканировании проверяется только 0Dh, а проверка 0Ah делается (на всякий случай после того как встретился 0D. > "первую строку не читаем (по тех. причинам)" Видать у тебя там 0D0A сидит (иначе бы твой код пропускал первую строку). А говоришь без оптимизации Что касается стиля, то при сканировании char* обычно не имеет смысла использовать индексы, проще инкрементировать сами указатели lpText и char* p = &buffer. Что собс-но и видим в стиле rgo, навеянном стилем Торвальдса etc ИМХО - классика )
rgo Спасибо. Хотя на мой взгляд дробление на мелкие процедуры только усложняет чтение кода. А цикл Код (Text): for (lpText = first_line (buffer, ch, &lpText[2]); lpText != NULL; lpText = next_line (buffer, ch, lpText)) Уж больно запутано выглядит. Или это правило такое: чем больше непонятности и абстракции, тем лучше Переделал процедуру так: Код (Text): void Fill_List(int buttonID) { char buffer[256]; char* lpText; int i=2; GetDlgItemText(hWnd, buttonID, buffer, 256); cr_strlcase(buffer); if ( buffer[0] < 0 ) lpText = (char*) lpRus; else lpText = (char*) lpEng; SendMessage (hList, LB_RESETCONTENT, 0, 0); while (i++) if ( buffer[0] == lpText[i] && *((short*) (lpText+i-2))==0x0A0D ) break; lpText += i; do { i = 0; while ( *((short*)(lpText+i))!=0x0A0D ) buffer[i++] = lpText[i]; buffer[i] = 0; lpText += i+2; SendMessage (hList, LB_ADDSTRING, 0, (LPARAM) buffer); } while ( *(lpText) == buffer[0] ); } Это тоже неправильный стиль?
Это упрощает Fill_List. Проще дорубить, что основная работа -- это цикл перебирающий строчки. Понятно что делается с каждой строчкой. А если добавить комменты к функциям, то станет понятно какие строчки перебираются. При этом потенциальный изучатель кода, будет иметь возможность даже не вникать в структуру buffer. нет неправильного стиля Стили бывают удобными, бывают неудобными, но это очень субъективно. Вот когда нету стиля, тогда сливай воду.
cresta Ну так придирайся ... ok. О программе в твоем сообщении Дата: Окт 26, 2005 00:07:34 Ошибки в логике: 1) "первую строку не читаем (по тех. причинам)" - надо искать первый конец строки, а не пропускать два байта 2) где проверка выхода за пределы lpText, т.е. как поведет себя программа, если в исходном файле нет слов на требуемую букву или буква соответствует последним строкам, т.е. что в буфере за данными. По поводу стиля: Наличие глобальных переменных, например, hWnd, lpRus, lpEng, hList - неудачное решение. По поводу алгоритма: Для нахождения слов на последнюю, или несуществующую, букву просматривается весь буфер/файл - это требует времени.
_DEN_ То с точки зрения системы. А с точки зрения организации кода — именно глобальная переменная. В случае наличия только 1 окна с hWnd выходит тоже самое. Или оборачивать hWnd в синглтон?
IceStudent А не надо судить об организации по конкретному коду. Смотри на идею в целом В винде только один синглтон - винда Остальное - объекты.
IceStudent глобальная hInstance — тоже "неудачное решение" Да. Или вопрос с подвохом? Ты знаешь, случаи, когда значение hInstance нельзя получить оперативно? На мой взгляд, любая глобальная переменная - неудачное решение, так как лишает код свободы. В данном случае код жестко привязан к конкретным буферам, окну с кнопками и listbox'у. Если посмотреть на задачу под другим углом, то необходимо из некоторого текстового файла найти строки, которые начинаются на определенный символ, т.е. входные параметры - имя файла и символ, выходные каким-либо образом организованный список строк. Над решением этой задачи и надо работать. Причем тут окна, кнопки и др. элементы управления?
q_q Поясняю: первая строка как минимум состоит из двух байт (0D0A), поэтому пропуская их, я всё равно не перескачу через начало второй строки. В самом удачном случае как раз на начале второй строки. Вот эта проверка (в самом конце процедуры): if ( *(lpText) != buffer[0] ) break; Я оговаривал, что память выделена VirtualAlloc, поэтому при достижениии конца текста в *(lpText) окажется ноль. Длина файла не кратна размеру страницы памяти, поэтому некоторое количество нулей будет обязательно. Первый же из них приведет к окончанию заполнения листа, т.к. буквы с кодом 0 нет. Вот два примера: поиск по последней букве (Z): а) время с занесением в лист при помощи SendMessage....LB_ADDSTRING - 16 мс а) время без занесения в лист (без SendMessage....LB_ADDSTRING) - 0 мс Вот ещё два примера: поиск по самой большой (в смысле кол-ва строк) букве (S): а) время с занесением в лист при помощи SendMessage....LB_ADDSTRING - 460 мс а) время без занесения в лист (без SendMessage....LB_ADDSTRING) - 0 мс Это показывает, что время, необходимое на занесение в список практически целиком определяется временем работы SendMessage. Поэтому оптимизировать эту процедуру, начиная поиск с предвычисленных (для каждой буквы) адресов смысла нет, хотя сначала именно так и было сделано: при чтении файла с диска в массив заносились адреса, с которых начиналась новая буква. Но оказалось, что овчинка не стоит выделки, поэтому эта квазиоптимизация была удалена. Если мы взвалили большой и тяжелый камень SendMessage на спину, нет никакого смысла сдувать с него пыль. Легче не станет О глобальных переменных и переносимости кода: при повторном использовании этой процедуры в другом приложении неплохо было бы хотя бы бегло просмотреть её, и заменить hList на что-то другое. Это правильней, чем наворачивать универсальность за счёт передачи нараметров через стек. ИМХО.
cresta Очень ошибочное имхо: copy/paste ни к чему хорошему не приводит. Разве что к появлению статей про индусских программистов
IceStudent Ну так а я о чём говорю: прежде чем делать copy/paste, надо хотя бы бегло просмотреть код, понять его работу. При этом и заметишь hList, и заменишь его на что-то другое. А универсализация на все случаи жизни - вот это и есть индусизация, чтобы индус просто взял и подключил универсальный кусок кода, не заглянув в него.
IceStudent Про оперативность vs глобальные переменные. Зависит от ситуации. cresta первая строка как минимум состоит из двух байт А если больше? Как поведет себе программа? Длина файла не кратна размеру страницы памяти ... Программа написана под конкретные два файла, которые никогда не будут меняться? Надеюсь, ты не думаешь, что размер страницы тоже зависит от размера этих файлов? Вот два примера ... Программа будет работать только на том компьютере, на котором производились измерения и одновременно с теме же запущенными приложениями? неплохо было бы хотя бы бегло просмотреть её, и заменить ... чем наворачивать универсальность Речь не об универсальности, а о выработке навыка писать код, который можно использовать (без анализа как и что он делает) в другой программе. В данном случае, можно реализовать следующие подпрограммы:<ul type=disc><li>LPDICTIONARY DictionaryOpen(LPTSTR pszFileName, DWORD dwFlags) - приготовиться к работе со словарем;<li>BOOL DictionaryClose(LPDICTIONARY pDictionary) - завершить работу со словарем;<li>LPDICTIONARIFIND DictionaryFindFirstWord(LPDICTIONARY pDictionary, char ch, char *pszBuffer, DWORD dwBufSize) - начать поиск слов;<li>BOOL DictionaryFindNextWord(LPDICTIONARIFIND pDictionaryFind, char *pszBuffer, DWORD dwBufSize) - продолжить поиск;<li>BOOL DictionaryFindClose(LPDICTIONARIFIND pDictionaryFind) - завершить поиск.</ul>
cresta Счастья в просмотре кода STL Если библиотека надёжна и документирована, то в код её заглядывать редко когда нужно. Это ведь время, которое лучше потратить на свой код.
IceStudent Это не ко мне )) Пусть stl'ом индусы пользуются. Я не поклонник стандартных либ и stl в частности. Надо мной не висит менеджер с угрозами увольнения, если работа не сделана в срок, поэтому я могу позволить себе каждую функцию реализовать с нуля, и мне пофиг, сколько времени я на неё потрачу. Это моё хобби, мне интересен сам процесс. q_q Программа написана под два файла с известными и фиксированными размерами. Обычный словарик. И если первая строка более 2 байт, то она всё равно пропустится. И на любом другом компе соотношения времени на процедуру с SendMessage и без неё будет примерно таким же. У тебя есть сомнения на этот счёт? Если не лень качать 700 кб зип, могу кинуть тебе готовую к проверке программу с файлами, проверишь Вот это принимается