8051 16 位 addition/multiplication 结果是 16 位而不是 32 位

8051 16 bit addition/multiplication result 16 bit instead of 32 bit

我有问题。在此程序中,变量 x 应设置为 0x10000,但在这两个操作中,结果均为 0。

这不是主程序,而是用来查找错误原因的测试。我目前正在制作一个带十六进制输入的 64 位乘法器。我使用 Keil 和 Proteus

使用 16 位乘法
int main() {
    unsigned long int x = 0;
    x = 0x8000 * 0x2;
    x = 0x8000 + 0x8000;
    return 0;
}

不清楚变量 x 应该是 0x10000。 x 是 unsigned long int,但您分配给它的值是 unsigned int。如果在该平台上 int 只有 16 位,则 0x8000 * 20x8000 + 0x8000 都是 0.

首先尝试使用 0x8000L(或更好的 0x8000UL)来创建长文字。

文字 0x8000 的类型为 unsigned int。在您的 16 位机器上,intunsigned int 的自然大小为 16 位,这是 C 标准接受的最小值。整数提升规则说较小宽度的类型被加宽到 intunsigned int,但没有进一步 (C11 n1570 6.3.1.1p2):

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. 58) All other types are unchanged by the integer promotions.

仅当 other 操作数具有更高的等级时,才会从 intunsigned int 扩大操作数。

这里,0x8000 + 0x8000是用unsigned int计算出来的,会折回0,因为unsigned int可以表示的最大值是0xFFFF.

您应该使用后缀 UL 或通过添加显式强制转换将至少一个操作数强制为 unsigned long

int main() {
    unsigned long int x=0;
    /* unsigned long int * int */
    x = 0x8000UL * 0x2;

    /* unsigned long + unsigned int */
    x = (unsigned long)0x8000 + 0x8000;
    return 0;
}

另请参阅 In a C expression where unsigned int and signed int are present, which type will be promoted to what type? 进行一般性讨论。