Разница между n = 0 и n = n - n - PullRequest
3 голосов
/ 15 мая 2009

Когда я прочитал этот вопрос, я вспомнил, как кто-то однажды сказал мне (много лет назад), что с точки зрения ассемблера эти две операции очень разные:

n = 0;

n = n - n;

Это правда, и если это так, то почему?

РЕДАКТИРОВАТЬ: Как указано в некоторых ответах, я думаю, компилятору было бы довольно легко оптимизировать то же самое. Но то, что я нахожу интересным, это то, почему они будут отличаться, если у компилятора будет совершенно общий подход.

Ответы [ 7 ]

10 голосов
/ 15 мая 2009

Написание ассемблерного кода, который вы часто используете:

xor eax, eax

вместо

mov eax, 0

Это потому, что с первым оператором у вас есть только код операции и никакой вовлеченный аргумент. Ваш процессор сделает это за 1 цикл (вместо 2). Я думаю, что ваш случай нечто подобное (хотя с использованием sub).

7 голосов
/ 15 мая 2009

Компилятор VC ++ 6.0, без оптимизаций:

4:        n = 0;
0040102F   mov         dword ptr [ebp-4],0
5:
6:        n = n - n;
00401036   mov         eax,dword ptr [ebp-4]
00401039   sub         eax,dword ptr [ebp-4]
0040103C   mov         dword ptr [ebp-4],eax
4 голосов
/ 15 мая 2009

Это может зависеть от того, объявлено n как volatile или нет.

4 голосов
/ 15 мая 2009

Оптимизирующий компилятор выдаст одинаковый код сборки для двух.

3 голосов
/ 15 мая 2009

В первые дни циклы памяти и процессора были недостаточны. Это приводит к множеству так называемых «оптимизаций». Давайте посмотрим на код:

move.l #0, d0

moveq.l #0, d0

sub.l a0,a0

Для первой инструкции потребуются два байта для кода операции, а затем четыре байта для значения (0). Это означало, что было потрачено четыре байта, плюс вам понадобится дважды обратиться к памяти (один раз для кода операции и один раз для данных). Sloooow.

moveq.l был лучше, так как он объединял данные в код операции, но позволял записывать значения только от 0 до 7 в регистр. И вы были ограничены только регистрами данных, быстрого способа очистки регистра адресов не было. Вам нужно очистить регистр данных, а затем загрузить регистр данных в регистр адресов (два кода операции. Плох.).

Для выполнения последней операции, которая работает с любым регистром, требуется всего два байта, одно чтение памяти. В переводе на С вы получите

n = n - n;

, который будет работать для наиболее часто используемых типов n (целое число или указатель).

2 голосов
/ 15 мая 2009

Техника на ассемблере обнуления регистра путем его вычитания из самого себя или XOR с самим собой интересна, но на самом деле она не переводится в C.

Любой оптимизирующий компилятор C будет использовать эту технику, если она имеет смысл, и попытка выписать ее явно вряд ли приведет к чему-либо.

1 голос
/ 15 мая 2009

не уверен насчет сборки и тому подобное, но, как правило,

n=0
n=n-n

не всегда равно, если n является плавающей точкой, см. Здесь http://www.codinghorror.com/blog/archives/001266.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...