当我在程序集中乘以一对4字节整数时,结果的下半部分在EAX中,EDX中的较高部分.如果我在C或C中,我想获得更高的部分,是否可能没有使用内联汇编?
以同样的方式可以得到EAX的整数除法结果和EDX的模数结果,而不会重复C或C的划分?我实际上只知道做第一个a / b,然后是一个%b,而在汇编器中,两个结果都是在同一个操作中给出的.
解决方法
你可以很容易地用C这样做:
#include <stdint.h> uint32_t a,b; // input uint64_t val = (uint64_t)a * b; uint32_t high = val >> 32,low = val;
把它留给编译器来生成最好的代码.现代优化器真的很好.手编组装通常看起来更好,但表现更差.
由Pete Becker评论,上述依赖于uint32_t和uint64_t类型的可用性.如果您坚持使用硬盘可移植性(例如您在DS9K上进行编程),则可以使用在C99下始终可用的类型uint_least32_t和uint_least64_t或uint_fast32_t和uint_fast64_t,但是您需要一个额外的掩码,如果不需要:
#include <stdint.h> uint_fast32_t a,b; // input uint_fast64_t val = (uint_fast64_t)a * b; uint_fast32_t high = (val >> 32) & 0xFFFFFFFF,low = val & 0xFFFFFFFF;
关于划分,您可以使用C99库函数div,ldiv或lldiv在一次调用中执行带符号除法和余数操作.如果可能,在特定操作数类型的目标架构上,分割/模组合将在一个操作中实现.
编写两个表达式可能会更有效,并依靠编译器检测模式并生成使用单个IDIV操作码的代码:
struct divmod_t { int quo,rem; }; struct divmod_t divmod(int num,int denom) { struct divmod_t r = { num / denom,num % denom }; return r; }
测试在Matt Godbolt’s compiler explorer显示clang和gcc生成一个单一的idiv指令这个代码在-O3.
你可以将其中一个分为一个乘法:
struct divmod_t { int quo,rem; }; struct divmod_t divmod2(int num,int denom) { struct divmod_t r; r.quo = num / denom; r.rem = num - r.quo * denom; return r; }
请注意,上述功能不会检查潜在的溢出,这会导致未定义的行为.如果denom = 0,并且如果num = INT_MIN和denom = -1,则发生溢出.