Це не стенограма.
+=
Символ з'явився на мові C в 1970 - х роках, а також - з ідеєю C «розумного асемблера» відповідає чітко іншого режиму команд машини і адресації:
Такі речі, як " i=i+1
", "i+=1
"і" ++i
", хоча на абстрактному рівні дають однаковий ефект, на низькому рівні відповідають різному способу роботи процесора.
Зокрема, ці три вирази, якщо припустимо, що i
змінна знаходиться в пам'яті, що зберігається в регістрі процесора (назвемо це D
- подумайте про це як "покажчик на int"), і ALU процесора приймає параметр і повертає результат у "акумулятор" (назвемо це A - подумайте на це як на int).
З урахуванням цих обмежень (дуже поширених у всіх мікропроцесорах того періоду), переклад, швидше за все, буде
;i = i+1;
MOV A,(D); //Move in A the content of the memory whose address is in D
ADD A, 1; //The addition of an inlined constant
MOV (D) A; //Move the result back to i (this is the '=' of the expression)
;i+=1;
ADD (D),1; //Add an inlined constant to a memory address stored value
;++i;
INC (D); //Just "tick" a memory located counter
Перший спосіб зробити це неоптимально, але він є більш загальним при роботі зі змінними замість постійних ( ADD A, B
або ADD A, (D+x)
) або при перекладі складніших виразів (всі вони збиваються при натисканні операції з низьким пріоритетом у стеку, виклику високого пріоритету, поп і повторюйте, поки всі аргументи не будуть усунені).
Другий більш характерний для "машини машини": ми вже не "оцінюємо вираз", а "керуємо значенням": ми все ще використовуємо ALU, але уникаємо переміщення значень, щоб результат міг замінити параметр. Цей вид інструкцій не можна використовувати там, де потрібні складніші висловлювання: i = 3*i + i-2
їх не можна використовувати на місці, оскільки i
це потрібно більше разів.
Третя - навіть простіша - навіть не розглядає ідею "додавання", але використовує більш "примітивну" (в обчислювальному сенсі) схему для лічильника. Інструкція скорочується, завантажується швидше і виконується негайно, оскільки комбінаторна мережа, необхідна для переобладнання реєстру, щоб зробити його лічильником, менша, а значить, швидша, ніж повна суматор.
У сучасних компіляторах (див. С, на даний момент), що дозволяє оптимізувати компілятор, відповідність може бути замінена на основі зручності, але все ще існує концептуальна різниця в семантиці.
x += 5
засоби
- Знайдіть місце, визначене x
- Додайте до нього 5
Але x = x + 5
означає:
- Оцініть х + 5
- Знайдіть місце, визначене x
- Скопіюйте х у акумулятор
- Додайте 5 до акумулятора
- Збережіть результат у х
- Знайдіть місце, визначене x
- Скопіюйте на нього акумулятор
Звичайно, оптимізація може
- якщо "пошук x" не має побічних ефектів, два "знаходження" можна зробити один раз (і x стати адресою, що зберігається в реєстрі покажчиків)
- дві копії можна видалити, якщо
&x
замість цього до акумулятора застосовано ADD
таким чином, роблячи оптимізований код, щоб він збігався x += 5
.
Але це можна зробити, лише якщо "пошук x" не має побічних ефектів, в іншому випадку
*(x()) = *(x()) + 5;
і
*(x()) += 5;
є семантично різними, оскільки x()
побічні ефекти (визнання x()
це функція, яка робить дивні речі навколо та повернення int*
) будуть вироблятися двічі або один раз.
Еквівалентність між x = x + y
і x += y
, отже, обумовлена конкретним випадком, коли +=
і =
застосовуються до прямого l-значення.
Щоб перейти на Python, він успадкував синтаксис від C, але оскільки немає перекладу / оптимізації перед виконанням інтерпретованих мов, речі не обов'язково так тісно пов'язані (оскільки є один крок менш синтаксичного аналізу). Однак інтерпретатор може посилатися на різні процедури виконання для трьох типів вираження, користуючись різними машинними кодами залежно від того, як формується вираз та від контексту оцінки.
Для тих, хто любить детальніше ...
Кожен процесор має ALU (арифметико-логічну одиницю), що є, по суті, комбінаторною мережею, входи та висновки якої "підключені" до регістрів та / або пам'яті залежно від опкоду інструкції.
Бінарні операції, як правило, реалізуються як "модифікатор реєстру акумулятора з входом, взятим" десь ", де десь може бути - всередині самого потоку інструкцій (типовий для контент-маніфесту: ADD A 5) - всередині іншого реєстру (типовий для обчислення вираження з temporaries: напр., ADD AB) - всередині пам'яті, за адресою, заданою реєстром (типово для отримання даних, наприклад: ADD A (H)) - H, в цьому випадку працюють як покажчик перенаправлення.
З цим псевдокодом, x += 5
є
ADD (X) 5
поки x = x+5
є
MOVE A (X)
ADD A 5
MOVE (X) A
Тобто, x + 5 дає тимчасовий, який пізніше призначається. x += 5
діє безпосередньо на х.
Фактична реалізація залежить від реального набору процесорів: Якщо ADD (.) c
опкоду немає , перший код стає другим: жодним чином.
Якщо такий опкод є, і оптимізація ввімкнена, другий вираз, усунувши зворотні ходи та відкоригувавши регістри опкоду, стане першим.
x += 5
ніжx = x + 5
? Або це справді просто синтаксичний цукор, як ви пропонуєте?