二进制补码形式的64位负整数

时间:2010-02-14 22:43:42

标签: c bit-manipulation bignum

我正在阅读GNU PDF库的源代码,特别是它们对64位整数的实现。他们将64位整数定义为两个32位整数的结构 - 高阶int是有符号的,低阶int是无符号的。以下是头文件中的相关代码:

/*Definition of internal structure of the pdf_i64_t type*/
struct pdf_i64_s
{
  pdf_i32_t   high;
  pdf_u32_t low;
};

typedef struct pdf_i64_s pdf_i64_t;

根据架构手册,负数以二进制补码形式表示。我对此功能有疑问:

[来自pdf-types.c的代码]

void pdf_i64_assign_quick (pdf_i64_t *bignum,
                      const pdf_i32_t value,
                  pdf_status_t *p_status)
{
  ASSIGN_SAFE(p_status, PDF_OK);

  if (bignum != NULL)
    {
      if (value < 0)
        {
          bignum->high = 0xFFFFFFFF;
        }
      else
        {
          bignum->high = 0;
        }
      bignum->low = value;
    }
  else
    {
      ASSIGN_SAFE(p_status, PDF_ERROR);
    }
}

根据我的阅读,要获得数字的二进制补码,您需要反转所有位并将结果加1。但是在上述函数中,对于值<0,它们只是将高阶位设置为0xFFFFFFFF,而根本不改变低阶位。不应该将'value'的位反转,然后加1?有人可以解释一下吗?

感谢。

4 个答案:

答案 0 :(得分:5)

你会注意到value已经已经一个有符号的32位整数 - 如果它是负数,它已经被正确地反转了。所有需要做的就是符号扩展。

答案 1 :(得分:3)

我认为你混淆了一些东西 - 用两个补码表示法否定一个数字,你翻转所有的位并添加一个。

虽然这里没有否定。这是存储一个值,并进行符号扩展 - 顶部位必须通过高32位扩展。这是正在发生的事情,因为输入已经签名,两个补码输入。

答案 2 :(得分:1)

Anon已经回答了这个问题,我只是想发布一个没有分支就做同样事情的轻微优化。

void pdf_i64_assign_quick (pdf_i64_t *bignum,
                      const pdf_i32_t value,
                  pdf_status_t *p_status)
{
  ASSIGN_SAFE(p_status, PDF_OK);

  if (bignum != NULL)
    {
      bignum->high = (value >= 0) - 1;
      bignum->low = value;
    }
  else
    {
      ASSIGN_SAFE(p_status, PDF_ERROR);
    }
}

对于-1,0xffffffff为32位十六进制,并且(值> = 0)计算为1或0,因此对于负值value,它也设置为0xffffffff,对于正值,设置为0。 / p>

答案 3 :(得分:0)

它说那个值是一个32位的int ...值已经是2s补码形式所以不需要改变