Только для добавления к тому, какие сказанные tvanfosson, много шаблонов выглядят одинаково до реализации. Таким образом, много сделайте, чтобы Вы создали интерфейс где, возможно, не было того прежде в Вашем коде, и затем создайте набор реализаций того интерфейса. Различие находится в их цели и как они используются.
Для отладки оптимизированного кода изучите ассемблер / машинный язык.
Используйте режим GDB TUI. Моя копия GDB включает его, когда я набираю минус и Enter. Затем введите Cx 2 (удерживая Control и нажмите X, отпустите оба и нажмите 2). Это поместит его в разделенный исходный код и дисплей разборки. Затем используйте stepi
и nexti
для перемещения одной машинной инструкции за раз. Используйте Cx o для переключения между окнами TUI.
Загрузите PDF-файл о машинном языке вашего процессора и соглашениях о вызове функций. Вы быстро научитесь распознавать, что делается с аргументами функции и возвращаемыми значениями.
Вы можете отобразить значение регистра, используя команду GDB, например p $ eax
Объявить найдено как «изменчивое». Это должно указать компилятору НЕ оптимизировать его.
volatile int found = 0;
Компилятор начнет делать очень умные вещи с включенной оптимизацией. Отладчик будет показывать, что код много прыгает вперед и назад из-за оптимизированного способа хранения переменных в регистрах. Вероятно, это причина, по которой вы не можете установить свою переменную (или в некоторых случаях увидеть ее значение), поскольку она была грамотно распределена между регистрами для скорости, вместо того, чтобы иметь прямую ячейку памяти, к которой может получить доступ отладчик.
Compile без оптимизаций?
Как правило, логические значения, которые используются в ветвях сразу после их вычисления, как это, никогда не сохраняются в переменных. Вместо этого компилятор просто выполняет переход непосредственно от кодов условий , которые были установлены из предыдущего сравнения. Например,
int a = SomeFunction();
bool result = --a >= 0; // use subtraction as example computation
if ( result )
{
foo();
}
else
{
bar();
}
return;
Обычно компилируется в нечто вроде:
call .SomeFunction ; calls to SomeFunction(), which stores its return value in eax
sub eax, 1 ; subtract 1 from eax and store in eax, set S (sign) flag if result is negative
jl ELSEBLOCK ; GOTO label "ELSEBLOCK" if S flag is set
call .foo ; this is the "if" black, call foo()
j FINISH ; GOTO FINISH; skip over the "else" block
ELSEBLOCK: ; label this location to the assembler
call .bar
FINISH: ; both paths end up here
ret ; return
Обратите внимание, что "bool" на самом деле нигде не сохраняется.
Вы практически не можете установить значение found. Отладка оптимизированных программ редко стоит хлопот, компилятор может переупорядочить код таким образом, чтобы он никоим образом не соответствовал исходному коду (кроме получения того же результата), тем самым беспредельно запутывая отладчиков.
При отладке оптимизированных программ (что может быть необходимо, если ошибка не обнаруживается в отладочных сборках), вам часто приходится понимать, что сгенерирован компилятором сборки.
В вашем конкретном случае return значение cpnd_find_exact_ckptinfo
будет храниться в регистре, который используется на вашей платформе для возвращаемых значений. На ix86
это будет % eax
. На x86_64
: % rax
и т. Д. Возможно, вам придется поискать в Google «соглашение о вызове процедуры [ваш процессор]», если это не соответствует ни одному из вышеперечисленных.
Вы можете проверить этот регистр в GDB
, и вы можете его установить. Например, на ix86
:
(gdb) p $eax
(gdb) set $eax = 0