Страница 1 из 1
Проблема компиляции - оптимизации программы VC++6.0
Добавлено: Сб фев 19, 2005 16:50
Parcan
пишу плагин на Visual C++ 6.0
1. дебаг версия работает отлично, если компилировать с любой оптимизацией, то некоторые участки кода работают некорректно.
Пример:
читаю из файла в структуру, в ней все ок, передаю по ссылке в функцию, некоторые поля оказываются нулевыми.
обращаюсь к файлу может возникнуть ошибка обращения.
КАК МОЖНО БОРОТСЯ С ОПТИМИЗАЦИЕЙ И ЕСТЬЛИ ИНФА ПО ЭТОМУ?
2. в итоге откомпилировал без оптимизации но с избавлением от дебаг инфы, все вроде работает, но на некоторых файлах вылетает ошибка о чтении по неверному адрусу памяти, причем если файл скопировать в другую папку или переименовать все нормально, в дебаг версии такого не возникает, в итоге пытался найти место где возникает ошибка, так она на одном и том же файле возникает в разных участках кода, короче так и не смог ничего понять. Получается что какаято оптимизация всеравно происходит? и вообще кто тут виноват я или мелкомянкие.
Ну и еще вопросы по организации кода
а) как можно прицепить свою таблицу акселераторов к листеру, чтоб ввести горячие клавиши?
б) создаю окна (tabcontrol, static, richedit) как потомки моего основного окна, так как только я им передаю фокус, то все сообщения уже не попадают в WndProc моего основного окна, что делать?
Добавлено: Сб фев 19, 2005 18:14
CaptainFlint
Parcan
1. При чтении из файла в структуру часто бывают глюки, когда не учитывается выравнивание элементов структуры по 4-байтным адресам. Ты уверен, что ошибка возникает именно на этапе передачи структуры в функцию, а не при чтении из файла?
Ещё бывают проблемы, когда некорректно используется динамическая память: в дебаге и в релизе у неё различная внутренняя реализация.
2. Возможно, забываешь закрыть файл или опять же - динамическая память.
Вообще, ошибки слишком уж общие, чтобы можно было сказать, в чём конкретно баги. Во всяком случае, винить мелкомягких надо не в первую, а в самую последнюю очередь. Я уже огромное число раз натыкался на всякого рода ошибки, ругался на глючный VC++, а потом оказывалось, что ошибка у меня в коде.
Добавлено: Сб фев 19, 2005 19:49
Dest
>а) как можно прицепить свою таблицу акселераторов к листеру, чтоб ввести горячие клавиши?
Посмотри RegiserHotKey в MSDN :)
Можно перехватывать мессаги лисеру, но для новичков это будет сложновато понять ...
Добавлено: Вс фев 20, 2005 12:08
Parcan
CaptainFlint
не читается все нормально и с выравниванием все ок, потеря происходит именно при передаче, такое ощущение, что часть структуры оседает в регистрах, это проявляется только при оптимизации кода.
с файлом тоже все нормально работаю, вообще участки кода в которых возникают ошибки после оптимизации я использую уже около 3 лет и я уверен что тут что-то с оптимизацией, поскольку у меня 18 классов унаследованы от одного и все используют одни и теже функции и после оптимизации ошибка может появится, а может и не появится
Пример:
вставляю в месте где собственно возникает ошибка sprintf() которая ничего нужного не делает и код после этого работат нормально, хоть убейте а в этом случае отличается только конечная реализация этого участка кода
с динамической памятью были когдато проблемы, но я с ней работаю 4 года и понял, что если все всегда инициализируешь и не оставляешь NULL то и проблем не будет при компиляции в релизе.
да и еще раньше код тестировался отдельным екзешником и там никаких проблем при компиляции в релизе не возникало, это появилось только тогда когда я весь код откомпилил в длл.
Вобщем самая главная проблемма в том, что я впервые в жизни не могу понять в чем проблема, хотя бьюсь уже около 2 недель
Добавлено: Вс фев 20, 2005 13:00
CaptainFlint
Parcan
В DLL своя специфика. Нельзя сказать, что если EXE работает, то и DLL будет, это абсолютно неверно. Я лично на это наткнулся, когда писал плагин VirtualDisk. Запускаю программу filedisk.exe - всё отлично работает, диск подключается. Запускаю абсолютно тот же самый код, но скомпилированный в виде DLL - при подключении диск в системе появляется, но все обращения к нему обламываются. В конце концов выяснил: там не закрывались некоторые хендлы. Отдельной программе это пофигу: при завершении система сама всё закроет. А DLL, пока не закроется Тотал, не будет выгружаться, так и держит хендлы открытыми, блокируя доступ.
И это лишь один пример. Сколько их может быть неучтённых... Оно часто так бывает - вроде, всё очевидно, ошибиться негде. Ан нет...
И ещё: частенько ошибки вылезают не в том месте, где их причина. Вполне может оказаться, что ошибка чуть ли не в самом начале кода, но проявляется она только после определённых действий, причём в таком месте, где весь код начисто вылизан и абсолютно корректен. Поиск ошибок - очень непростое занятие...
А вообще, подобные обсуждения без собственно кода - это переливание из пустого в порожнее. Попробуй хоть как-то локализовать ошибку, урезать проект как можно сильнее, чтобы ошибка по-прежнему воспроизводилась, и выложи в общий доступ. Тогда, возможно, кто-то и найдёт, в чём проблема. Ну или в самом деле, докажет, что ошибка в компиляторе (такое тоже, конечно, не исключено, хотя и маловероятно). Кстати говоря, сервис-паки на студию установлены? А то мало ли...
Добавлено: Вс фев 20, 2005 15:20
Ipse
Parcan
Пример:
вставляю в месте где собственно возникает ошибка sprintf() которая ничего нужного не делает и код после этого работат нормально, хоть убейте а в этом случае отличается только конечная реализация этого участка кода
У меня такое было несколько раз. Во всех случаях в ошибке были виноваты строковые операции. Где-то что-то недовыделил. Если там действительно строки (или вообще любые массивы), то проблему можно решить в лоб применением винапишных safe-функций (правда, совместимость с 9х может пострадать).
Добавлено: Вс фев 20, 2005 23:53
Parcan
ПРИМЕР1: вот пример код нерабочий после оптимизации и код рабочий после оптимизации
//неработает
int TAce::
AnalyzeArcHead(ACE_BLOCK_HEAD& head)
{
WORD HEAD_SIZE = 0;
//...
HEAD_SIZE = TakeWord(head.HEAD_SIZE1, head.HEAD_SIZE2);
//...
m_loffset = HEAD_SIZE + 4;
//...
}
//гдето вызов
m_MSG = AnalyzeArcHead(m_BLOCK_HEAD);
посмтотрел через MessageBox() head.HEAD_SIZE1 и head.HEAD_SIZE2 равны 0, хотя m_BLOCK_HEAD.HEAD_SIZE1 и m_BLOCK_HEAD.HEAD_SIZE2 имеют значения, в итоге m_loffset = 0 + 4 = 4
//работает
int TAce::
AnalyzeArcHead(ACE_BLOCK_HEAD& head)
{
WORD HEAD_SIZE = 0;
//...
//начало ненужной вставки
char BufStr[MAX_LOADSTRING];
sprintf(BufStr, "%d\n%d", head.HEAD_SIZE1, head.HEAD_SIZE2);
//конец ненужной вставки
HEAD_SIZE = TakeWord(head.HEAD_SIZE1, head.HEAD_SIZE2);
//...
m_loffset = HEAD_SIZE + 4;
//...
}
//гдето вызов
m_MSG = AnalyzeArcHead(m_BLOCK_HEAD);
опять компилирую с оптимизацией, опа в head.HEAD_SIZE1 и head.HEAD_SIZE2 находятся нужные мне значения
мое мнение, что в первом случае нужные мне значения оказались только в регистрах процессора, а не в нужной мне структуре (после чтения из файла), во втором случае компилятор всетаки решил записать значения в мою структуру... КАКИЕ БУДУТ МЫСЛИ?
ПРИМЕР2
//при запуске плагина
HFONT hFontB = ::CreateFont(12, 0, 0, 0, FW_BOLD, FALSE, FALSE,
FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_ROMAN, "MS Sans Serif");
HFONT hFontN = ::CreateFont(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE,
FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_ROMAN, "MS Sans Serif");
HFONT hFontS = ::CreateFont(24, 0, 0, 0, FW_BOLD, FALSE, TRUE,
FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_ROMAN, "MS Sans Serif");
//при завершении работы
if (hFontB) { ::DeleteObject(hFontB); hFontB = 0; }
if (hFontN) { ::DeleteObject(hFontN); hFontN = 0; }
if (hFontS) { ::DeleteObject(hFontS); hFontS = 0; }
в MSDN написано либо будет создан шрифт, либо вернется NULL, соответственно я полагаю, что тут все должно отрабатывать корректно, вылавливал ошибку на участке удаления шрифтов...
все что я создаю в динамической памяти я инициализирую и даже на всякий случай удаляю в обратном порядке создания, проверил уже ну все, все что я делаю сам через new-delete проверил на 100%...
НЕДОУМЕНИЕ
и последнее есть у кого-нибудь предположение как возникновение ошибок может быть связано с путем файла и его именем, ведь как я уже говорил, что когда я находил такие ситуации я копировал или переименовывал файл и никаких ошибок на копии или переименованном оригинале не проявлялось, но на самом файле оригинале(непереименованном) возникают 100%. Все это проверялось только на Win98SE, на работе проверить все никак нет времени.
Ipse
ну незнаю сколько на си пишу а со строками всегда проблемы решаемы, поскольку покрайней мере на моей практике, ошибка со строками либо вылезает еще в дебаг версии, либо при первом запуске релиз версии.
Dest
RegisterHotKey, по тексту MSDN мне показалось, что хоткей будет срабатывать всегда независимо от текущего фокуса, хотя я в английском слаб могу и ошибатся, а как перехватывать сообщения хоть наметку дай, если будет время то меня не ломает поразбиратся, я вообще думал что на WinAPI писать легче, а когда попробовал (это впервый раз) аж офигел вспомнилось как на 1-2 курсах ассемблер изучали.
Добавлено: Пн фев 21, 2005 13:39
Ipse
Parcan
мое мнение, что в первом случае нужные мне значения оказались только в регистрах процессора, а не в нужной мне структуре (после чтения из файла), во втором случае компилятор всетаки решил записать значения в мою структуру...
Это как? Передается адрес уже заполненной структуры:
m_BLOCK_HEAD.HEAD_SIZE1 и m_BLOCK_HEAD.HEAD_SIZE2 имеют значения
и по дороге мистическим образом данные _переместились_ из памяти в регистры?
Если можно поподробнее кусок с заполнением структуры m_BLOCK_HEAD и полную процедуру парсинга AnalyzeArcHead()
Добавлено: Пн фев 21, 2005 19:05
Parcan
Ipse
вставлять много давай на мыло кину
кстати я вдруг подумал в функции TakeWord() у меня используется ассемблерная вставка, может она както влияет, хотя во всех остальных местах при вызове функция сбоев не дает
//sobrat' WORD iz BYTEs
//lb - mladshiy BYTE
//hb - starshiy BYTE
WORD TArchive::
TakeWord(BYTE lb, BYTE hb)
{
WORD wrd = 0;
_asm
{
push eax
mov ah, hb //0xXX00
mov al, lb //0x00XX
mov wrd, ax //0xXXXX
pop eax
}
return wrd;
}
хотя как это при оптимизации может помешать ума не приложу.
Добавлено: Пн фев 21, 2005 21:17
Ipse
Мыло в приват кинул.
Врядли глючит асмовая вставка, но можно попробовать следующий изврат:
WORD* HEAD_SIZE = (WORD*) (&head.HEAD_SIZE1); // ИМХО, самый красивый вариант
естественно,
BYTE HEAD_SIZE1;
BYTE HEAD_SIZE2;
должны быть объявлены рядом при определении структуры.
или так:
WORD HEAD_SIZE = head.HEAD_SIZE1;
HEAD_SIZE = ( HEAD_SIZE << 8 ) + head.HEAD_SIZE2;
про MAKEWORD() молчу, полагаю заменен сознательно (профайлер рулит ?)
Добавлено: Вт фев 22, 2005 18:36
Parcan
Ipse
когда я себе представляю данные в регистрах я предпочитаю делать асмовские вставки, имхо нагляднее
выслал на мыло