为什么sscanf会忽略指定的宽度?

时间:2012-11-27 11:11:33

标签: c++ hex scanf

我正在使用此代码将固定大小为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修复它,并在每一步中复制到数组。)

重现:

#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 光盘 EF 01 23 45 67 89 AB 光盘 EF 10 11 12 13

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

01 23 ... 光盘 EF 00 00 00 13

4 个答案:

答案 0 :(得分:4)

您的代码在开始时存在一个小问题。

const uint8_t* c = "0123456789abcdef0123456789abcdef";

在C ++中,未指定charsigned还是unsigned。更确切地说,类型 charsigned charunsigned 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说明符。

答案 1 :(得分: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
$ 

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

答案 2 :(得分: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

答案 3 :(得分:1)

c ++解决方案 with iostream 可能如下:

  #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] << " ";
  }