如何将BCD转换为十进制?

11
我怎样将二进制编码的十进制数转换为其对应的十进制数字,而不是它的值?我想要的是转换显示方式,而非它的值。例如,我想把0x11转换为十进制数11(而不是17),把0x20转换为20(而不是32)。
unsigned char day = 0x11;
unsigned char month = 0x12;

int dayDecimal, monthDecimal;

我希望 dayDecimal 的值为 11,monthDecimal 的值为 12。我将使用 0x00 到 0x60 的范围,所以应该是可行的。不会出现 'A'、'B'、'C'、'D'、'E'、'F'。

更新:

实际上,我正在读取 RTCC 芯片中的时间,作为我正在开发的嵌入式项目的一部分。小时、分钟、日和月以那种形式返回。例如,如果分钟为 0x40,则表示 40 分钟而不是 64,因此需要正确保持其解释。我需要以某种方式将 0x40 转换为 40 而不是 64。我希望这是可能的。

谢谢!


0x11 是一个数字字面量。它只是一个数字;它既不是十六进制也不是十进制。十六进制只是一种显示数字的方式。 - SLaks
我希望这只是一个学术练习... - sled
4
它正在寻求将BCD(二进制编码十进制)值转换为其十进制等价值。虽然有点不寻常,但这并不罕见。实际上,Z80芯片有支持BCD加法和减法的指令。 - Jonathan Leffler
2
@sled BCD曾经相当普遍。显然,它浪费了一小部分存储空间,但它使编码数据更易于人类阅读。例如,如果时间戳被打包为BCD,则可以从消息的二进制数据转储中快速提取它。 - M.M
@MattMcNabb 谢谢你的见解 - 每天都有新东西可以学习。 - sled
3个回答

19

你需要使用两个半字节,将较高位的半字节乘以十并加上较低位的半字节:

uint8_t hex = 0x11;
assert(((hex & 0xF0) >> 4) < 10);  // More significant nybble is valid
assert((hex & 0x0F) < 10);         // Less significant nybble is valid
int dec = ((hex & 0xF0) >> 4) * 10 + (hex & 0x0F);
如果禁用了断言但输入错误(例如0xFF),那么您就会得到应有的结果:GIGO - 垃圾进去,垃圾出来。 您可以轻松地将其包装成一个(内联)函数:
static inline int bcd_decimal(uint8_t hex)
{
    assert(((hex & 0xF0) >> 4) < 10);  // More significant nybble is valid
    assert((hex & 0x0F) < 10);         // Less significant nybble is valid
    int dec = ((hex & 0xF0) >> 4) * 10 + (hex & 0x0F);
    return dec;
}       

这种转换让人想起了BCD - 二进制编码十进制


我不确定你是如何想到uint8_t和assert的,这对我来说不太清楚。顺便说一下,请检查一下我的问题更新。 - Ammar
2
在大多数系统中,uint8_t(来自<stdint.h>)等同于unsigned char。实际上,我认为可以安全地说,如果系统提供了uint8_t,那么它就等同于unsigned char,但该类型在理论上是可选的。如果您不喜欢它,可以将类型更改为unsigned char,而不会影响功能。断言的作用是确保您对所声称的有效输入诚实无误。如果您从未提供虚假数据,则断言永远不会触发。如果您不喜欢断言,并且不介意冒险,可以删除断言。 - Jonathan Leffler
基本上代码应该长这样:“unsigned hex = 0x60; int dec = ((hex & 0xF0) >> 4) * 10 + (hex & 0x0F);”,顺便说一下,我认为你是正确的。我需要测试一下来确认它。 - Ammar
你说得对,谢谢。我自己想不出来,非常感激。 - Ammar

14

一个非常简单的方法,没有错误检查:

int bcd_to_decimal(unsigned char x) {
    return x - 6 * (x >> 4);
}

1
不错的解决方案,花了我一分钟才算出数学问题。所以,假设我们有:0x34 == 3 * 0x10 + 4 == 3 * 16 + 4 == 3 * 10 + 3 * 6 + 4 == 30 + 3 * 6 + 4 == 34 + 3 * 6 == 34 + (0x34 >> 4) * 6,这给了我们这个结果:34 == 0x34 - (0x34 >> 4) * 6。 - scope

1
把所需的值放入函数中,就会得到一个整数作为返回值。
#include <stdio.h>
#include <math.h>

typedef int                 INT32;

typedef short int           INT16;

typedef unsigned short int  UINT16;

typedef unsigned long int   UINT32;

UINT32 BCDToDecimal(UINT32 nDecimalValue){
    UINT32 nResult=0;
    INT32  nPartialRemainder, ncnt,anHexValueStored[8];
    UINT16 unLengthOfHexString = 0,unflag=0;

    for(ncnt=7 ;ncnt>=0 ; ncnt--){
        anHexValueStored[ncnt]=nDecimalValue & (0x0000000f << 4*(7-ncnt));
        anHexValueStored[ncnt]=anHexValueStored[ncnt] >> 4*(7-ncnt);
        if(anHexValueStored[ncnt]>9)
        unflag=1;
    }
    if(unflag==1){
        return 0;
    }
    else{
        for(ncnt=0 ;ncnt<8 ; ncnt++)
        nResult= nResult +anHexValueStored[ncnt]*pow(10,(7-ncnt));
        return nResult;
    }
}
int main() {
    printf("%ld\n",BCDToDecimal(0X20));
    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接