sprintf将十六进制数组转换为十进制char数组只读取第一个字节

时间:2018-03-29 20:06:41

标签: c arrays hex printf decimal

我有一个数组:

unsigned char datalog[4];
datalog[0] = 0;
datalog[1] = 0xce;
datalog[2] = 0x50;
datalog[3] = 0xa3;

这些代表十六进制值0xce50a3。其十进制值为13521059。

我需要将此十六进制值转换为十进制数组,最好使用sprintf,以便最终结果为:

finalarray[0] = '1';
finalarray[1] = '3';
finalarray[2] = '5';
finalarray[3] = '2';
finalarray[4] = '1';
finalarray[5] = '0';
finalarray[6] = '5';
finalarray[7] = '9';

我尝试了几种sprintf输入组合,包括将我的十六进制数组连接到unsigned long datalogvalue = 0xce50a3。但sprintf只在转换时读取其第一个字节。

例如:

sprintf(finalarray, "%d", *(unsigned long *)datalog);

的产率:

finalarray[0] = '2';
finalarray[1] = '0';
finalarray[2] = '6';
finalarray[3] = ' ';
.....

206是0xce的十进制表示。所以它只转换第一个十六进制字节,而不是其余的。

有关如何将整个无符号长整数转换为十进制数组的想法吗?

5 个答案:

答案 0 :(得分:1)

char*转换为unsigned long*并取消引用该指针的结果取决于系统的字节顺序。除非这个特定计算的效率对于你的程序的性能至关重要,否则不要使用这些技巧。使用简单的逻辑。

int res = (datalog[0] << 24) +
          (datalog[1] << 16) +
          (datalog[2] << 8) +
          datalog[3];

sprintf(finalarray, "%d", res);

如果您需要使用unsigned long作为类型,请务必在unsigned long的调用中使用sprintf的正确格式说明符。

unsigned long res = (datalog[0] << 24) +
                    (datalog[1] << 16) +
                    (datalog[2] << 8) +
                    datalog[3];

sprintf(finalarray, "%lu", res);

答案 1 :(得分:1)

正如其他人提到的那样,尝试按顺序读取数组的字节将依赖于系统,因为Big Endian和Little Endian系统会产生不同的结果。

此外,通过指针欺骗进行类型惩罚是未定义的行为,因为它打破了严格的别名。将pun类型键入char-family数组以外的类型的合法方法涉及使用联合以多种方式表示数据。但是,由于上面的Endian问题,你不应该为这个问题做到这一点,而是采用R Sahu的回答中提到的位移方法。

答案 2 :(得分:1)

一种简单的解决方案,不依赖于endian,int大小或指针技巧

形成值

//              LU to use unsigned long math
((datalog[0]*256LU + datalog[1])*256 + datalog[2])*256 + datalog[3]

打印

sprintf(finalarray, "%lu", value);

sprintf(finalarray, "%lu", 
    ((datalog[0]*256LU + datalog[1])*256 + datalog[2])*256 + datalog[3]);

答案 3 :(得分:0)

由于字节顺序,字节不会按照您认为的顺序出现:

IDEOne Link

#include <stdio.h>

int main(void) {
unsigned char datalog[4];
char finalarray[20] = {0};

datalog[0] = 0xa3;
datalog[1] = 0x50;
datalog[2] = 0xce;
datalog[3] = 0x00;

sprintf(finalarray, "%lu", *(unsigned long*)datalog);

printf("Answer: %s\n", finalarray);
return 0;
}

<强> 输出

Success #stdin #stdout 0s 4180KB
Answer: 13521059

答案 4 :(得分:0)

首先,字节序使得事情在这里变得麻烦。 为了能够将缓冲区重新解释为32位int,在打包时必须考虑字节序。

例如,在我的little-endian系统上,如果将数据转换为32位无符号整数,则数据记录将被解释为:2739981824。

因此,我必须根据以下示例中的datalog2打包我的数据,以获得所需的13521059.

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

int main() {

    uint8_t datalog[4];
    datalog[0] = 0;
    datalog[1] = 0xce;
    datalog[2] = 0x50;
    datalog[3] = 0xa3;

    uint32_t temp = *((uint32_t*) datalog);

    printf("%u\n", temp); // 2739981824


    uint8_t datalog2[4];
    datalog2[0] = 0xa3;
    datalog2[1] = 0x50;
    datalog2[2] = 0xce;
    datalog2[3] = 0;

    uint32_t temp2 = *((uint32_t*) datalog2);

    printf("%u\n", temp2); // 13521059

    return 0;
}

但是你要问的是另一个问题。

如果我正确地解释了你的问题,你想得到另一个数组,其中每个小数组成13951059在基数10中,最终在它自己的索引中。

为了做到这一点,你必须能够用每个索引来解决log2(10)位,这是不可能的。

因此,为了获得您建议的包装数组,您必须手动转换它。