解释一个将uint32转换为十六进制的函数



我希望有人向我解释一下在我的工作中发现的代码库中的这个奇怪的函数。

bool uint32tox(const UINT32 input, UINT8 *str)
{
    UINT32 val = input;
    INT16  i;
    UINT16  j = 0;
    if (str == NULL) return(false);
    for (i = 28; i >= 0; i -= 4) {
        UINT8 sval = (val >> i) & 0x0F;
        str[j++] = (sval < 10u) ? sval + '0' : sval - 10 + 'A';
    }
    str[j] = '';
    return(true);
}

为什么以0x0F开头,为什么以28开头

我冒昧地给代码加了一点注释

/*
  Convert an unsigned 32-bit (assuming UINT32 to mean uint32_t or similar) large
  integer to a hexadecimal representation
*/
bool uint32tox(const UINT32 input, UINT8 *str)
{
    UINT32 val = input;
    INT16  i;
    UINT16  j = 0;
    if (str == NULL) return(false);
    for (i = 28; i >= 0; i -= 4) {
        // Shift input by i bits to the right and snip of the rightmost 4 bits
        /*
            0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
            with i = 28 sval contains the leftmost four bits 28 - 31
            with i = 24 sval contains bits 24-27
            with i = 20 sval contains bits 20-23
            with i = 16 sval contains bits 16-19
            with i = 12 sval contains bits 12-15
            with i =  8 sval contains bits  8-11
            with i =  4 sval contains bits  4- 7
            with i =  4 sval contains bits  0- 3
        */
        UINT8 sval = (val >> i) & 0x0F;
        // If sval is smaller than ten we can use a base ten digit
        // that gets constructed by adding the numerical value of ASCII '0'
        // to sval (the digits 0-9 are guaranteed to be in order without gaps).
        // If sval is bigger we need a hexdigit, one of A, B, C, D, E, F.
        // These are normally consecutive at least in ASCII, so you can handle it
        // like the other branch and just add the numerical value of 'A' instead
        str[j++] = (sval < 10u) ? sval + '0' : sval - 10 + 'A';
    }
    // terminate the UINT8 array such that it can be used as a C-string
    str[j] = '';
    return(true);
}

首先,这个函数是坏的,因为它没有*str缓冲区的大小,可能导致恶意攻击,或者纯粹的bug溢出。

其次,您可以使用sprintf(strOut, "%x",input);代替此函数。

第三,我将解释这个函数:

有一个技巧,其中每个十六进制数字,是4个二进制位:

0100 1111 0010 1101 0011 1110 1111 0000 >> 83,022,831
4 =4 15=F 2 =2 13=D 3 =3 14=E 15=F 0 =0 >> 0x4F2D3EF
  1. 循环开始于i=28
  2. shift val右移28位>>左移4位[28-31]作为最右位。
  3. 带0x00000F>>的掩码只留下最右边的4位。
  4. 如果数字小于10(我们开始用字母计数),添加ASCII '0'(例如3将'0'是48 + 3 = 51 = '3')
  5. 如果数字大于10,则减去10,并添加'A'的ASCII(例如14将是14-10=4> 'A'是65 + 4 = 69 = 'E')
  6. 从i中减去4,因此移动24位,并且对位进行相同的操作[24-27]直到i=0被处理。

最新更新