Используйте этот код в Windows, если вы хотите отключить редактирование пользователя и разрешите Ctrl + C для копирования текста экрана:
def txtEvent(event):
if(event.state==12 and event.keysym=='c' ):
return
else:
return "break"
txt.bind("<Key>", lambda e: txtEvent(e))
Stack space for local variables is usually allocated in function scope. So no stack pointer adjustment happens inside the loop, just assigning 4 to var
. Therefore these two snippets have the same overhead.
Для примитивных типов и типов POD это не имеет значения. Компилятор выделит пространство стека для переменной в начале функции и освободит его, когда функция вернется в обоих случаях.
Для типов классов, не относящихся к POD, которые имеют нетривиальные конструкторы, это БУДЕТ иметь значение - в этом случае размещение переменной вне цикла вызовет конструктор и деструктор только один раз, а оператор присваивания - на каждой итерации, тогда как помещение его внутри цикла вызовет конструктор и деструктор для каждой итерации цикла. В зависимости от того, что делают конструктор, деструктор и оператор присваивания класса, это может быть или нежелательно.
They are both the same, and here's how you can find out, by looking at what the compiler does (even without optimisation set to high):
Look at what the compiler (gcc 4.0) does to your simple examples:
1.c:
main(){ int var; while(int i < 100) { var = 4; } }
gcc -S 1.c
1.s:
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $0, -16(%ebp)
jmp L2
L3:
movl $4, -12(%ebp)
L2:
cmpl $99, -16(%ebp)
jle L3
leave
ret
2.c
main() { while(int i < 100) { int var = 4; } }
gcc -S 2.c
2.s:
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $0, -16(%ebp)
jmp L2
L3:
movl $4, -12(%ebp)
L2:
cmpl $99, -16(%ebp)
jle L3
leave
ret
From these, you can see two things: firstly, the code is the same in both.
Secondly, the storage for var is allocated outside the loop:
subl $24, %esp
And finally the only thing in the loop is the assignment and condition check:
L3:
movl $4, -12(%ebp)
L2:
cmpl $99, -16(%ebp)
jle L3
Which is about as efficient as you can be without removing the loop entirely.
В наши дни лучше объявляйте его внутри цикла, если только он не является константой, поскольку компилятор сможет лучше оптимизировать код (уменьшив область действия переменной).
РЕДАКТИРОВАТЬ: Этот ответ в настоящее время в основном устарел. С появлением постклассических компиляторов случаи, когда компилятор не может это понять, становятся редкими. Я все еще могу их построить, но большинство людей классифицируют конструкцию как плохой код.
Большинство современных компиляторов оптимизируют это за вас. При этом я бы использовал ваш первый пример, так как считаю его более читаемым.
Для встроенного типа, вероятно, не будет никакой разницы между 2 стиля (вероятно, вплоть до сгенерированного кода).
Однако, если переменная представляет собой класс с нетривиальным конструктором / деструктором, вполне может быть большая разница в стоимости выполнения. Я бы обычно ограничивал переменную внутри цикла (чтобы область была как можно меньше), но если это окажет влияние на производительность, я бы посмотрел, чтобы переместить переменную класса за пределы области цикла. Однако для этого требуется некоторый дополнительный анализ, поскольку семантика пути оды может измениться, поэтому это можно сделать только в том случае, если сематика позволяет это.
Классу RAII может потребоваться такое поведение. Например, класс, который управляет временем жизни доступа к файлу, может потребоваться создать и уничтожить на каждой итерации цикла для правильного управления доступом к файлу.
Предположим, у вас есть класс LockMgr
, который получает критическую секцию при создании и выпуске при уничтожении:
while (i< 100) {
LockMgr lock( myCriticalSection); // acquires a critical section at start of
// each loop iteration
// do stuff...
} // critical section is released at end of each loop iteration
сильно отличается от:
LockMgr lock( myCriticalSection);
while (i< 100) {
// do stuff...
}
Оба контура имеют одинаковую эффективность. Оба они займут бесконечное количество времени :) Возможно, стоит увеличить i внутри циклов.
Единственный способ убедиться - это рассчитать время. Но разница, если она есть, будет микроскопической, поэтому вам понадобится очень большая петля синхронизации.
Говоря точнее, первый вариант лучше, потому что он инициализирует переменную var, а второй оставляет ее неинициализированной. Это и указание о том, что переменные следует определять как можно ближе к месту их использования, означает, что обычно предпочтительнее первая форма.
При наличии только двух переменных компилятор, скорее всего, назначит регистр для обеих. Эти регистры в любом случае есть, так что это не займет времени. В любом случае имеется 2 инструкции записи и одна инструкция чтения регистра.
это неправда есть накладные расходы, однако их игнорируемые накладные расходы.
Даже если они, вероятно, окажутся в одном и том же месте в стеке, он все равно присваивает их. Он назначит ячейку памяти в стеке для этого int, а затем освободит ее в конце}. Не в смысле без кучи, в смысле, он переместит sp (указатель стека) на 1. И в вашем случае, учитывая, что у него есть только одна локальная переменная, он просто будет приравнивать fp (указатель кадра) и sp
Короткий ответ будет: НЕ ЗАНИМАЙТЕСЬ, ЛЮБОЙ СПОСОБ РАБОТАЕТ ПОЧТИ ЖЕ.
Но попробуйте прочитать больше о том, как стек организовано. В моей старшей школе читались неплохие лекции по этому поводу. Если вы хотите узнать больше, проверьте здесь http://www.cs.utk.edu/~plank/plank/classes/cs360/360/notes/Assembler1/lecture.html