Вопрос

В ассемблере я могу использовать команду 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-битный результат. На уровне языка у вас нет доступа к такому умножению.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top