基于8个十六进制字节创建无符号整数

时间:2012-10-04 01:14:42

标签: c hex bit-shift

我正在尝试将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的一些研究的结果。

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

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

1 个答案:

答案 0 :(得分:1)

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

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

#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,其字节顺序与字符串中的字节顺序相反。那是因为你所谓的小端架构。

所以你有两个问题。

首先,您要按错误的顺序处理字节以获取原始数字。

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

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

第二个是你正在以错误的顺序进行添加/移位操作。

由于您的原始代码在添加后移动,因此它转到D2029649,然后将其向左移动8位,从而导致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

显示您正在取回原始号码。