0

我正在尝试将 an 打印unsigned int为十六进制,但不仅仅是使用%08X. 我需要先用 MSB 打印每个字节的 MSB 和 LSB 的十六进制。我已经明白了:

unsigned int num = 1234567890;
char *p = (char*)#
for (int i = 0; i < 4; i++) {
    printf("%X%X", (*(p+i) & 0xF0) >> 4, *(p+i) & 0x0F);
}
// prints: D2029649

但是,我无法unsigned int从包含以下内容的字符串返回D2029649

short dehex(char hexLetter) {
  if(hexLetter > 47 && hexLetter < 58) hexLetter -= 48;
  if(hexLetter > 64) hexLetter -= 55;
  return hexLetter;  
}

unsigned int o = 0;
char *in = "D2029649";
int len = strlen(in);
for(int i = 0; i < len; i++) {
    if(i % 2 == 0) {
        o |= ((unsigned char)dehex(in[i]) << 4) + dehex(in[i+1]);
        o <<= 8;
    }
}

不用说,这根本行不通。这两行代码操作o是我尝试撤消原始编码所做的工作以及我对如何将字节转回 int 所做的一些研究的结果。

也许我的麻烦来自对我在生成十六进制时实际在做什么的完全误解。

有没有人有任何提示让我朝着正确的方向前进,将十六进制带回原始的无符号整数?

4

1 回答 1

1

您练习的目的似乎是根据其内存布局将整数转换为字符串,然后再将其转换回来。

否则,您不会试图弄清楚您是否在字节边界上,然后进行位移“体操”。相反,您只需将值左移四位并添加下一个数字,例如:

#include <stdio.h>
#include <string.h>

short dehex (char hexLetter) {
    if ((hexLetter >= '0') && (hexLetter <= '9'))
        return hexLetter - '0';
    return hexLetter - 'A' + 10;
}

int main (void) {
    unsigned int o = 0;
    char *in = "D2029649";
    int len = strlen (in);
    for (int i = 0; i < len; i++)
            o  = (o << 4) + dehex (in[i]);
    printf ("%X\n", o);
    return 0;
}

你会注意到我已经dehex稍微改变了函数,因为我不是魔术数字的忠实粉丝,其中字符常量更具可读性(它仍然不能移植到所有实现,例如 EBCDIC,但现在很少有这样的实现)。

该程序将以大写十六进制输出该字符串中的无符号整数值以进行检查:D2029649

但是,1234567890十进制值是十六进制的,499602D2字节的顺序与字符串中的字节顺序相反。那是因为您使用的是所谓的小端架构。

所以你有两个问题。

首先是您以错误的顺序处理字节以取回原始号码。

您需要从字符串的末尾开始并向后工作,例如:

for (int i = len - 2; i >= 0; i -= 2) ...

第二个是您以错误的顺序执行添加/移位操作。

因为您的原始代码在添加之后移动,所以它到达D2029649然后向左移动八位,导致02964900-D2从左侧移动到遗忘,并且在右侧移动零字节。您需要转移然后添加:

o <<= 8;
o |= ((unsigned char)dehex(in[i]) << 4) + dehex(in[i+1]);

最后,虽然不是必需的,但如果您只使用 unsigned char 返回转换后的 nybble,您可以大大简化您的代码。我将编写的代码如下:

#include <stdio.h>
#include <string.h>

unsigned char dehex (char hexLetter) {
    if ((hexLetter >= '0') && (hexLetter <= '9'))
        return hexLetter - '0';
    return hexLetter - 'A' + 10;
}

int main (void) {
    unsigned int num = 1234567890;
    char *p = (char*) &num;
    for (int i = 0; i < 4; i++)
        printf("%X%X", (*(p+i) & 0xF0) >> 4, *(p+i) & 0x0F);
    putchar ('\n');

    unsigned int o = 0;
    char *in = "D2029649";
    int len = strlen (in);
    for (int i = len - 2; i >= 0; i -= 2) {
        o <<= 8;
        o |= (dehex (in[i]) << 4) + dehex (in[i+1]);
    }
    printf ("%X, or %u\n", o, o);
    return 0;
}

请注意,就一次处理一个字节而不是一次处理一个 nybble 而言,这更有意义。使用基于 nybble 的代码,您必须按顺序执行数组索引,6, 7, 4, 5, 2, 3, 0, 1而不是一个漂亮的0..7小循环。

这个程序的输出是:

D2029649
499602D2, or 1234567890

表明您正在取回您的原始号码。

于 2012-10-04T01:24:44.063 回答