3

我正在使用此代码将固定大小为 32 的十六进制字符串转换为 16 字节的 uint8 数组。

const uint8_t* c = "0123456789abcdef0123456789abcdef";
uint8_t Bytes[16];
for (int i = 0; i < 16; i++) {
    sscanf (&c[2*i], "%2hhx", &(Bytes[i]));
}

尽管hh指定了 1 个字节的目标宽度,但每步写入 4 个字节。因此,代码在缓冲区末尾写入 3 个字节。这是为什么?

(现在,我使用临时 int 修复它,该临时 int 在每一步都被复制到数组中。)

重现:

#include <stdint.h>
#include <string>

void main (int argc, char* argv[])
{
    const char* c = "0123456789abcdef0123456789abcdef";
    uint8_t b[20];
    for (int i = 0; i < 20; i++) {
        b[i] = i;
    }
    for (int i = 0; i < 16; i++) {
        sscanf (&c[2*i], "%2hhx", &(b[i]));
    }
    for (int i = 0; i < 20; i++) {
        fprintf(stdout,  "%02x\n", (int)(b[i]));
    }
}

预期输出为 01 23 45 67 89 ab cd ef 01 23 45 67 89 ab cd ef 10 11 12 13

但是,使用 Visual Studio 2010 的实际输出是:

01 23 ... cd ef 00 00 00 13

4

4 回答 4

4

您的代码一开始就有一个小问题。

const uint8_t* c = "0123456789abcdef0123456789abcdef";

在 C++ 中,没有指定 acharsigned还是unsigned。更准确地说,类型 char, signed char,unsigned char是不同的,实际上在重载函数和专门化模板时必须考虑到这一点。

现在的代码是:

const char* c = "0123456789abcdef0123456789abcdef";
uint8_t Bytes[16];
for (int i = 0; i < 16; i++) {
    sscanf (&c[2*i], "%2hhx", &(Bytes[i]));
}

让我们分析您的格式字符串:

2  : maximum field witdh to be read
hh : expecting a pointer to signed or unsigned char
x  : means unsigned hex-input

(http://linux.die.net/man/3/scanf)

有了这个信息,到目前为止它看起来是正确的。

据我所知,符合 C99 的库 *没有问题。


*:在这方面,MSVC 库不支持说明hh符。

于 2012-11-27T11:48:54.767 回答
1

我在 Mac OS X 上使用 gcc 4.2.1 构建并运行了以下代码:

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

int main(void)
{
    const char *c = "0123456789abcdef0123456789abcdef";
    uint8_t b[20] = { 0 };
    int i;

    for (i = 0; i < 20; i++) {
        b[i] = i;
    }

    for (i = 0; i < 16; i++) {
        sscanf (&c[2*i], "%2hhx", &b[i]);
    }

    for (i = 0; i < 20; i++) {
        printf("%02x", b[i]);
    }
    printf("\n");

    return 0;
}

它似乎表现得如预期:

$ gcc -v
...
gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
$ gcc -Wall scanf_hex.c
$ ./a.out 
0123456789abcdef0123456789abcdef10111213
$ 

请尝试使用您的编译器等构建和运行上述代码,以便我们查看它是否可能是编译器/库错误,或者是否是您的代码中的其他问题。(您可能想尝试调试和发布版本。)

于 2012-11-27T11:29:47.270 回答
1

非常适合我:

#include <stdio.h>
#include <stdint.h>
int main()
{
    const char* c = "0123456789abcdef0123456789abcdef";
    unsigned char Bytes[16];
    int i;
    for (i = 0; i < 16; i++)
    {   
            sscanf (&c[2*i], "%2hhx", &(Bytes[i]));
    }   
    for (i=0; i < 16; ++i)
    {   
        fprintf(stdout,  "%02x\n", (int)(Bytes[i]));
    }   
}

使用:

> gcc gh.c 
> ./a.out
01
23
45
67
89
ab
cd
ef
01
23
45
67
89
ab
cd
ef
于 2012-11-27T11:50:02.380 回答
1

带有 iostream的 c++ 解决方案可能如下:

  #include<iostream>
  #include<sstream>
  #include<iomanip>      
  using namespace std;

  //...

  const char* c = "0123456789abcdef0123456789abcdef";
  unsigned char Bytes[16];
  stringstream s_in(c);
  for (int i = 0; i < 16; i++) 
  {
      string s;
      s_in >> setw(2) >> s;
      unsigned int t;
      stringstream(s) >> hex >> t;
      Bytes[i] = t;
  }

请注意,如果变量类型不是字符串,s_in 不想服从 setw(2)。如果变量是 char 类型,宽度也一定是 1 因此从 int 转换。

要测试它:

  for (int i = 0; i < 16; i++) 
  {
    cout << setfill('0') << setw(2) << hex << (int) Bytes[i] << " ";
  }
于 2012-11-27T14:35:56.130 回答