len(di)
равно 4. Таким образом, цикл
for i in range(len(di)):
будет повторяться 4 раза. Поскольку range
работает (от нижней границы, которая по умолчанию равна 0, если она не указана, до 1 под верхней границей), i
будет 0
в первом повторении, 1
во втором повторении , и так далее. Чтобы вычислить, сколько объектов range(x, y)
генерирует, в этом случае, как часто for i in range(x, y)
будет повторяться, вы можете просто сделать number of repetitions = y - x
. Так что в этом случае: len(di) - 0 (default lower bound) = 4
.
Цикл
for j in range(i+1, len(di)):
print(i)
будет повторять команду print(i)
len(di) - (i + 1)
раз. Имейте в виду, i
определяется внешней петлей. Итак, во время первого цикла
for i in range(len(di)):
i
равно 0
, поэтому команда print(i)
будет выполнена 4 - (0+1) = 3
раз - она напечатает i(=0)
3 раза. Во втором цикле i
равен 1, поэтому он будет напечатан 2 раза и так далее. Итак, вот что происходит, отформатировано как код для лучшей читаемости:
First outer loop:
i = 0
total = di[i] = di[0] = 96
--> first inner loop of first outer loop:
j = i + 1 = 1
i is printed -> prints 0
second inner loop of first outer loop:
j = j+1 = 2
i is printed -> prints 0 again
third inner loop of first outer loop:
j = j+1 = 3 --> since len(di) = 4, the upper bound of range(i+1, len(di)) is reached, so this is the last Repetition
i is printed -> prints 0 again
Second outer loop:
i = 1
total = di[1] = 15
--> first inner loop of second outer loop:
j = i+1 = 2
i is printed -> prints 1
second inner loop of second outer loop:
j = i+1 = 3 -> upper bound of range reached, last repetition
i is printed -> prints 1 again
Third outer loop:
i = 2
total = di[2] = 33
--> first inner loop of third outer loop:
j = i+1 = 3 -> upper bound of range is reached, only Repetition
i is printed -> prints 2
Fourth (and final) outer loop:
i = 3 -> upper bound of range(len(di)) reached, last Repetition
total = di[3] = 87
since j = i+1 = 4, the inner loop does not get executed at all (both bounds of range are equal), so 3 doesn't get printed
end of code.
Структурированная обработка исключений Windows (SEH) имеет двухфазную структуру. Когда возникает исключение, Windows сначала ищет обработчик исключения, следуя зарегистрированной цепочке обработчиков исключений (заголовок которой хранится в fs: [0] на x86, то есть первое двойное слово в сегменте, на который указывает сегмент FS. register - вся эта уродливая 16-битная логика смещения сегментов не исчезла в 32-битном, она просто стала менее актуальной).
Поиск выполняется путем вызова функции с определенным флагом, указатель на который сохраняется в каждом кадре исключения в стеке. fs: [0] указывает на самый верхний фрейм. Каждый кадр указывает на предыдущий кадр. В конечном счете, последний кадр в списке - это тот, который был предоставлен ОС (этот обработчик отобразит диалоговое окно сбоя приложения, если до него доходит необработанное исключение).
Эти функции обычно проверяют тип исключения и возвращают код, указывающий, что делать. Один из кодов, которые могут быть возвращены, - это, по сути, «игнорировать это исключение и продолжить».Если Windows это увидит, она сбросит указатель инструкции на точку исключения и возобновит выполнение. Другой код указывает, что этот кадр исключения должен обрабатывать данное исключение. Третий код: «Я не собираюсь ловить это исключение, продолжайте поиск». Windows продолжает вызывать эти функции фильтра исключений, пока не найдет тот, который так или иначе обрабатывает исключение.
Если Windows находит тот, который обрабатывает исключение, перехватывая его, то она переходит к раскручиванию стека обратно к этому обработчику, который состоит из повторного вызова всех функций, только с передачей другого флага. Именно в этот момент функции выполняют логику , наконец,
, вплоть до обработчика, который выполняет логику кроме
.
Однако, с исключением защиты страницы стека, процесс отличается. Ни один из обработчиков исключений языка не решит обрабатывать это исключение, потому что в противном случае механизм роста стека сломается. Вместо этого поиск с фильтром фильтрует весь путь до базового обработчика исключений, предоставляемого ОС, который увеличивает выделение стека, фиксируя соответствующую память, а затем возвращает соответствующий код возврата, чтобы указать, что ОС должна продолжить работу с того места, где она остановилась, а не раскручивать стек.
Инструментальные средства и инфраструктура отладки предназначены для правильного воспроизведения этих конкретных исключений, поэтому вам не нужно беспокоиться об их обработке.
Вы можете прочитать больше о SEH в отличной статье Мэтта Питрека в MSJ, написанной более десяти лет назад .
From looking at the comments, it looks to me like the "guard page exception" mess takes place entirely within the kernel, and is not something that you need to be worrying about from user space.
You've gotta remember that this article was written for C++, which is nowhere near as advanced as Delphi on the memory management front. The uninitialized pointers issue is a lot less of a mess in Delphi than in C/C++ for two reasons: