Проблема компиляции - оптимизации программы VC++6.0
Select messages from
# through # FAQ
[/[Print]\]

Total Commander -> Написание плагинов для Total Commander

#1: Проблема компиляции - оптимизации программы VC++6.0 Author: ParcanLocation: Russian PostPosted: Sat Feb 19, 2005 17:50
    —
пишу плагин на Visual C++ 6.0

1. дебаг версия работает отлично, если компилировать с любой оптимизацией, то некоторые участки кода работают некорректно.
Пример:
читаю из файла в структуру, в ней все ок, передаю по ссылке в функцию, некоторые поля оказываются нулевыми.
обращаюсь к файлу может возникнуть ошибка обращения.
КАК МОЖНО БОРОТСЯ С ОПТИМИЗАЦИЕЙ И ЕСТЬЛИ ИНФА ПО ЭТОМУ?

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




Ну и еще вопросы по организации кода
а) как можно прицепить свою таблицу акселераторов к листеру, чтоб ввести горячие клавиши?
б) создаю окна (tabcontrol, static, richedit) как потомки моего основного окна, так как только я им передаю фокус, то все сообщения уже не попадают в WndProc моего основного окна, что делать?

#2:  Author: CaptainFlintLocation: Москва PostPosted: Sat Feb 19, 2005 19:14
    —
Parcan
1. При чтении из файла в структуру часто бывают глюки, когда не учитывается выравнивание элементов структуры по 4-байтным адресам. Ты уверен, что ошибка возникает именно на этапе передачи структуры в функцию, а не при чтении из файла?
Ещё бывают проблемы, когда некорректно используется динамическая память: в дебаге и в релизе у неё различная внутренняя реализация.

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

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

#3:  Author: DestLocation: Беларусь(Минск,Барановичи) PostPosted: Sat Feb 19, 2005 20:49
    —
>а) как можно прицепить свою таблицу акселераторов к листеру, чтоб ввести горячие клавиши?
Посмотри RegiserHotKey в MSDN :)
Можно перехватывать мессаги лисеру, но для новичков это будет сложновато понять ...

#4:  Author: ParcanLocation: Russian PostPosted: Sun Feb 20, 2005 13:08
    —
CaptainFlint
не читается все нормально и с выравниванием все ок, потеря происходит именно при передаче, такое ощущение, что часть структуры оседает в регистрах, это проявляется только при оптимизации кода.

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

Пример:
вставляю в месте где собственно возникает ошибка sprintf() которая ничего нужного не делает и код после этого работат нормально, хоть убейте а в этом случае отличается только конечная реализация этого участка кода

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

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

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

#5:  Author: CaptainFlintLocation: Москва PostPosted: Sun Feb 20, 2005 14:00
    —
Parcan
В DLL своя специфика. Нельзя сказать, что если EXE работает, то и DLL будет, это абсолютно неверно. Я лично на это наткнулся, когда писал плагин VirtualDisk. Запускаю программу filedisk.exe - всё отлично работает, диск подключается. Запускаю абсолютно тот же самый код, но скомпилированный в виде DLL - при подключении диск в системе появляется, но все обращения к нему обламываются. В конце концов выяснил: там не закрывались некоторые хендлы. Отдельной программе это пофигу: при завершении система сама всё закроет. А DLL, пока не закроется Тотал, не будет выгружаться, так и держит хендлы открытыми, блокируя доступ.

И это лишь один пример. Сколько их может быть неучтённых... Оно часто так бывает - вроде, всё очевидно, ошибиться негде. Ан нет...

И ещё: частенько ошибки вылезают не в том месте, где их причина. Вполне может оказаться, что ошибка чуть ли не в самом начале кода, но проявляется она только после определённых действий, причём в таком месте, где весь код начисто вылизан и абсолютно корректен. Поиск ошибок - очень непростое занятие...

А вообще, подобные обсуждения без собственно кода - это переливание из пустого в порожнее. Попробуй хоть как-то локализовать ошибку, урезать проект как можно сильнее, чтобы ошибка по-прежнему воспроизводилась, и выложи в общий доступ. Тогда, возможно, кто-то и найдёт, в чём проблема. Ну или в самом деле, докажет, что ошибка в компиляторе (такое тоже, конечно, не исключено, хотя и маловероятно). Кстати говоря, сервис-паки на студию установлены? А то мало ли...

#6:  Author: Ipse PostPosted: Sun Feb 20, 2005 16:20
    —
Parcan
Quote:
Пример:
вставляю в месте где собственно возникает ошибка sprintf() которая ничего нужного не делает и код после этого работат нормально, хоть убейте а в этом случае отличается только конечная реализация этого участка кода


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

#7:  Author: ParcanLocation: Russian PostPosted: Mon Feb 21, 2005 00:53
    —
ПРИМЕР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 курсах ассемблер изучали.

#8:  Author: Ipse PostPosted: Mon Feb 21, 2005 14:39
    —
Parcan

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


Это как? Передается адрес уже заполненной структуры:

Quote:
m_BLOCK_HEAD.HEAD_SIZE1 и m_BLOCK_HEAD.HEAD_SIZE2 имеют значения


и по дороге мистическим образом данные _переместились_ из памяти в регистры?

Если можно поподробнее кусок с заполнением структуры m_BLOCK_HEAD и полную процедуру парсинга AnalyzeArcHead()

#9:  Author: ParcanLocation: Russian PostPosted: Mon Feb 21, 2005 20:05
    —
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;
}

хотя как это при оптимизации может помешать ума не приложу.

#10:  Author: Ipse PostPosted: Mon Feb 21, 2005 22:17
    —
Мыло в приват кинул.

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

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() молчу, полагаю заменен сознательно (профайлер рулит ?)

#11:  Author: ParcanLocation: Russian PostPosted: Tue Feb 22, 2005 19:36
    —
Ipse
когда я себе представляю данные в регистрах я предпочитаю делать асмовские вставки, имхо нагляднее

выслал на мыло



Total Commander -> Написание плагинов для Total Commander


output generated using printer-friendly topic mod. All times are GMT + 4 Hours

Page 1 of 1

Powered by phpBB © 2001, 2005 phpBB Group