3

我在 C 中有以下方法,它需要两个 16 位短整数和:

  • 将两个整数相加
  • 如果设置了进位标志,则将结果加 1
  • 否定(NOT)最终结果中的所有位
  • 返回结果:

    short __declspec(naked) getchecksum(short s1, short s2)
    {
        __asm
        {
            mov ax, word ptr [esp+4]
            mov bx, word ptr [esp+8]
            add ax, bx
            jnc skip_add
            add ax, 1
            skip_add:
            not ax      
            ret
        }
    }
    

我不得不在内联汇编中编写它,因为我不知道不使用汇编程序来测试进位标志的任何方法。有谁知道这样做的方法?

4

2 回答 2

5

不(C 根本没有标志的概念),但这并不意味着你不能得到相同的结果。如果使用 32 位整数进行加法,则第 17 位是进位。所以你可以这样写:

uint16_t getchecksum(uint16_t s1, uint16_t s2)
{
    uint32_t u1 = s1, u2 = s2;
    uint32_t sum = u1 + u2;
    sum += sum >> 16;
    return ~sum;
}

我已将类型设为无符号以防止出现问题。这在您的平台上可能不是必需的。

于 2014-11-07T18:05:15.813 回答
3

您不需要访问标志来执行更高精度的算术。如果总和小于任何一个操作数,则有进位,所以你可以这样做

short __declspec(naked) getchecksum(short s1, short s2)
{
    short s = s1 + s2;
    if ((unsigned short)s < (unsigned short)s1)
        s++;
    return ~s;
}

已经有很多关于添加和进行 SO 的问题:Efficient 128-bit add using carry flag , Multiword addition in C

然而,在 C 中,操作总是至少以 int 类型完成,因此您可以简单地添加,如果 int 在您的系统中有超过 16 位。在您的情况下,内联程序集是 16 位 x86,所以我猜您使用的是 Turbo C,应该尽快摆脱它(原因:为什么不使用 Turbo C++?)。在其他具有 16 位 int 的系统中,您可以使用 long,标准保证至少为 32 位

short __declspec(naked) getchecksum(short s1, short s2)
{
    long s = s1 + s2;
    return ~((s & 0xffff) + ((s >> 16) & 0x1));
}
于 2014-11-07T18:31:18.550 回答