3

このコードを使用して、固定サイズ 32 の 16 進文字列を 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]));
}

ターゲット幅を 1 バイトに指定しているにもかかわらず、hhステップごとに 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 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++ では、 a が であるか であるかは指定されていcharませsignedunsigned。より正確には、型 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指定子をサポートしていません。

于 2012-11-27T11:48:54.767 に答える
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 に答える
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 に答える