Вопрос
В ассемблере я могу использовать команду mul и получить 64-битный результат EAX: edx, как я могу сделать то же самое в C? http://siyobik.info/index.php?module=x86&id=210.
Мой подход к использованию uint64_t и сдвига результат не работает ^^
Спасибо за вашу помощь (=
Мне
Решение
Любой порядочный компилятор будет просто сделай это Когда спросили.
Например, используя VC ++ 2010, следующий код:
unsigned long long result ;
unsigned long a = 0x12345678 ;
unsigned long b = 0x87654321 ;
result = (unsigned long long)a * b ;
генерирует следующий ассемблер:
mov eax,dword ptr [b]
mov ecx,dword ptr [a]
mul eax,ecx
mov dword ptr [result],eax
mov dword ptr [a],edx
Другие советы
Опубликовать какой-нибудь код. Это работает для меня:
#include <inttypes.h>
#include <stdio.h>
int main(void) {
uint32_t x, y;
uint64_t z;
x = 0x10203040;
y = 0x3000;
z = (uint64_t)x * y;
printf("%016" PRIX64 "\n", z);
return 0;
}
Посмотреть, сможете ли вы получить эквивалент __emul или __emulu Для вашего компилятора (или просто используйте это, если у вас есть компилятор MS). Хотя 64 -битный умножение должно автоматически работать, если вы не будете сидеть за некоторым ограничением или другой забавной проблемой (например, _aulmul)
Вы хотите умножить два 32-битных количества, чтобы получить 64-битный результат?
Это не предвидится в C, либо у вас есть 32 бит в таких как uint32_t
И тогда результат имеет ту же ширину. Или вы бросаете до uint64_t
Но затем вы потеряете преимущество этого особого (и быстрого) умножения.
Единственный способ, которым я вижу, это использовать inline Assembler Extensions. GCC довольно хорош в этом, вы можете производить довольно оптимальный код. Но это не переносимо между разными версиями компиляторов. (Многие компиляторы общественных домен принимают GCC, хотя, я думаю)
#включать
/* The name says it all. Multiply two 32 bit unsigned ints and get
* one 64 bit unsigned int.
*/
uint64_t mul_U32xU32_u64(uint32_t a, uint32_t x) {
return a * (uint64_t)b; /* Note about the cast below. */
}
Это производит:
mul_U32xU32_u64:
movl 8(%esp), %eax
mull 4(%esp)
popl %ebp
ret
При компиляции с:
gcc -m32 -O3 -fomit-frame-pointer -S mul.c
Который использует mul
Инструкция (называется mull
Здесь для умножения Long, как это нравится ассемблер GNU для X86) так, как вы хотите.
В этом случае один из параметров был вытащен непосредственно из стека, а не помещается в реестр ( 4(%esp)
вещь означает 4 байта над указателем стека, а 4 байта, пропущенных, являются обратным адресом), потому что числа были переданы в функцию и были бы выдвинуты в стек (согласно x86 ABI (бинарный интерфейс приложения)).
Если вы включили функцию или просто сделали математику в вашем коде, это, скорее всего, приведет к использованию mul
Инструкция во многих случаях, хотя оптимизация компиляторов может также заменить некоторые умножения более простым кодом, если они могут сказать, что это будет работать (например, это может превратить это в сдвиг или даже постоянную, если один или несколько аргументов были известны).
В C коде из C по меньшей мере один из аргументов должен был быть отброшен до 64 битного значения, чтобы компилятор привел бы 64-битный результат. Даже если компилятор должен был использовать код, который создал 64-битный результат при умножении 32 битных значений, возможно, не считать верхней половиной, чтобы быть важным, потому что в соответствии с правилами C операций обычно приводит к значению с тем же типом Поскольку значение с наибольшим диапазоном из его компонентов (за исключением того, что вы иногда можете утверждать, что это не совсем то, что он делает).
Вы не можете сделать именно это в C, то есть вы не можете умножить два n-битных значения и получить 2n-битное значение в качестве результата. Семантика умножения C отличается от умножения вашей машины. В C оператор умножения всегда применяется к значениям одного и того же типа T
(так называемый Обычные арифметические преобразования позаботьтесь об этом) и дает результат того же типа T
.
Если вы работаете в переполнении на умножение, вы должны использовать более крупный тип для операндов. Если нет больших типов, вы не повезли (т.е. у вас нет другого выбора, кроме как использовать реализацию библиотечного уровня большого умножения).
Например, если самый большой целочисленный тип вашей платформы-64-битный тип, то на уровне сборки на вашей машине у вас есть доступ к mul
Операция, создающая правильный 128-битный результат. На уровне языка у вас нет доступа к такому умножению.