将负十进制转换为C中的二进制

时间:2018-11-23 11:49:45

标签: c binary decimal

我目前正在开发一个程序,该程序必须将十进制数转换为二进制,八进制和十六进制。 此代码已经可以使用:

    int e = 0;
    }
        while(i != 0){
            str[e] = (i%b) + '0';
            i = i / b;
            if(str[e] > '9'){
                str[e] = str[e] + 7;
            }
            e++;

    }
    if(vorzeichen == -1){
        str[e] = '1';
        e++;
    }
    if(b == 16){
        str[e] = 'x';
        str[e+1] = '0';
    }
    else if(b == 8){
        str[e] = '0';
    }
}

b是基数(二进制为2,八进制为8,六进制为16),而i是我要转换的数字。 这给出了一个字符串,然后我反转以获得正确的数字。现在,如果我尝试使用负数,则它不仅给出包含0和1的字符串,而且还给出/,在ASCII表上为'0'-1。对于八进制和十进制,它还会在ASCII表的'/'下方给出字符。我尝试了不同的可能解决方案,但似乎都没有给出理想的结果。我在互联网上读到的是,我必须使用2s补码,但我一直试图使用它。它似乎对我不起作用。

3 个答案:

答案 0 :(得分:1)

如果要显示负十进制,只需将int转换为unsigned int即可:

unsigned int value = (unsigned int)i;

现在,您只需在程序中使用value而不是i,就可以了。 这很好地解释了为什么:Converting negative decimal to binary

答案 1 :(得分:1)

在不同的基数/基数之间进行转换时,请始终对无符号整数类型起作用。

假设您有long num个您想转换。使用unsigned long u。要以二进制补码形式表示负值,可以使用

if (num < 0)
    u = 1 + (~(unsigned long)(-num));
else
    u = num;

或更短

unsigned long  u = (num < 0) ? 1 + (~(unsigned long)(-num)) : num;

这适用于所有体系结构(num == LONG_MIN除外,在这种情况下,上述技术上在技术上是未定义的行为),即使内部不使用二进制补码的那些,因为我们本质上都会转换num绝对值。如果num最初是负数,那么我们对无符号值进行两个补数。


在评论中,chux建议了另一种不依赖UB的形式num == LONG_MIN(除非LONG_MAX == ULONG_MAX,这是非常奇怪的事情):

unsigned long  u = (num < 0) ? 1 + (~((unsigned long)(-1 - num) + 1)) : num;

这看起来“丑陋”,但是一个理智的C编译器应该能够完全优化带有二进制补码整数的体系结构中的任何一个。 chux的版本通过从num中减去负数-1来避免未定义的行为,从而将-1映射到0,将-2映射到1,依此类推,确保所有负值都可表示为非负long。然后将该值转换为unsigned long。该值增加1,以说明较早的-1。此过程将得出num的正确否定。

换句话说,要获得long的绝对值,可以使用

unsigned long  abs_long(const long  num)
{
    return (num < 0) ? (unsigned long)(-1 - num) + 1u : (unsigned long)num;
}

答案 2 :(得分:0)

%是余数函数,不是 mod

对于b==2i%b返回[-1,0,1]。 str[e] = (i%b) + '0';不需要此功能,请参见... difference between “mod” and “remainder”

这是'/'的原因,并且“还在'/'下方给出了字符。


从“右侧”构建字符串

使用2的补码int,一种简单的方法是转换为unsigned并避免来自%的否定结果。由于代码使用%提取最低有效数字,因此将缓冲区从右移到左。

#include <limits.h>

...
unsigned u = i;

// make a temporary buffer large enough for any string output in binary
//           v------v Size of `u` in "bytes"
//           |      |   v------v Size of a "byte" - commonly 8
char my_buff[sizeof u & CHAR_BIT + 1];
int e = 0;

// Form a pointer to the end so code assigns the least significant digits on the right
char *p = &my_buff[sizeof my_buff - 1];

// Strings are null character terminated
*p = '\0';

// Use a `do` loop to insure at least one pass. Useful when `i==0` --> "0"
do {
  p--; 
  p[e] = "0123456789ABCDEF"[u%b];  // Select desired digit
  u = u / b;
} while (u);

// "prepend" characters as desired
if(b == 16){
  *(--p) = 'x';
  *(--p) = '0';
}
else if(b == 8 && i != 0){
  *(--p) = '0';
}

strcpy(str, p);