获取整数的负号并将其存储为char的最佳方法是什么?

ph7*_*ph7 2 c int char negative-number

如何获取整数的符号并将其存储在char中?一种方法是:

int n = -5
char c;
if(n<0)
    c = '-';
else
    c = '+';
Run Code Online (Sandbox Code Playgroud)

要么:

char c = n < 0 ? '-' : '+';
Run Code Online (Sandbox Code Playgroud)

但是有没有条件的方法吗?

PSk*_*cik 5

这会在x86-64上使用gcc / clang创建无分支的代码:

void storeneg(int X, char *C)
{
    *C='+';
    *C += (X<0)*('-'-'+');
}
Run Code Online (Sandbox Code Playgroud)

https://gcc.godbolt.org/z/yua1go


Lun*_*din 5

有一种最高效,最便携式的方法,但是它并没有赢得任何美容大奖。

我们可以假设有符号整数的MSB始终为负。即使考虑到异国签名格式(一个补码,一个符号大小),这也是100%可移植的假设。因此,最快的方法是简单地从整数中屏蔽掉MSB。

在位置可以找到任何整数的MSB CHAR_BIT * sizeof(n) - 1;。在典型的32位主流系统上,该值例如为8 * 4 - 1= 31。

因此,我们可以编写如下函数:

_Bool is_signed (int n)
{
  const unsigned int sign_bit_n = CHAR_BIT * sizeof(n) - 1;
  return (_Bool) ((unsigned int)n >> sign_bit_n);
}
Run Code Online (Sandbox Code Playgroud)

在x86-64 gcc 9.1(-O3)上,这会产生非常有效的代码:

is_signed:
        mov     eax, edi
        shr     eax, 31
        ret
Run Code Online (Sandbox Code Playgroud)

此方法的优点还在于,与诸如之类的代码不同x < 0,在移植时,它不会冒被翻译成“如果否定分支”指令的风险。

完整的例子:

#include <limits.h>
#include <stdio.h>

_Bool is_signed (int n)
{
  const unsigned int sign_bit_n = CHAR_BIT * sizeof(n) - 1;
  return (_Bool) ((unsigned int)n >> sign_bit_n);
}

int main (void)
{
  int n = -1;

  const char SIGNS[] = {' ', '-'};
  char sign = SIGNS[is_signed(n)];
  putchar(sign);
}
Run Code Online (Sandbox Code Playgroud)

拆卸(x86-64 gcc 9.1(-O3)):

is_signed:
        mov     eax, edi
        shr     eax, 31
        ret
main:
        sub     rsp, 8
        mov     rsi, QWORD PTR stdout[rip]
        mov     edi, 45
        call    _IO_putc
        xor     eax, eax
        add     rsp, 8
        ret
Run Code Online (Sandbox Code Playgroud)