hack のためのネタ帳, etc,,,

状況

C++ で OpenSSL をライブラリとして用いて
MD5, SHA1, SHA256, SHA512 等のメッセージダイジェストを求めた後、16進表示したかった。

そこで、「std::string hex」でググって出てきた とか
stringstream hex padding」でググって出てきた 辺りを参考に、
以下のようなコードを書いたのだが

sstest.cpp

#include <iostream>
#include <sstream>
#include <iomanip>

int main(int argc, char * argv[])
{
  unsigned char x[] = {0x01, 0x23, 0x45, 0x67};
  std::stringstream ss;
  ss << std::setfill('0') << std::hex;
  for (int i = 0; i < sizeof(x); i++) {
    ss << std::setw(2);
    ss << x[i];
  }
  std::cout << ss.str() << std::endl;
  return 0;
}
結果が
$ g++ sstest.cpp && ./a
0#Eg
みたいになった。

原因と対策

どうも、char や unsigned char を食わせるのが良くないらしい。
数値ではなく文字扱いされているという事のようだ。

static_cast で short や int に直してやると大丈夫だった。

sstest2.cpp

#include <iostream>
#include <sstream>
#include <iomanip>

int main(int argc, char * argv[])
{
  unsigned char x[] = {0x01, 0x23, 0x45, 0x67};
  std::stringstream ss;
  ss << std::setfill('0') << std::hex;
  for (int i = 0; i < sizeof(x); i++) {
    ss << std::setw(2);
    ss << static_cast<int>(x[i]);
  }
  std::cout << ss.str() << std::endl;
  return 0;
}
結果
$ g++ sstest2.cpp && ./a
01234567

差分
$ diff sstest{,2}.cpp
12c12
<     ss << x[i];
---
>     ss << static_cast<int>(x[i]);

static_cast を使うとどうも野暮ったいので暗黙の型変換を使ったほうがコンパクトで読み易いだろうか?
$ diff sstest{,3}.cpp
12c12
<     ss << x[i];
---
>     ss << 0 + x[i];
$ diff sstest{2,3}.cpp
12c12
<     ss << static_cast<int>(x[i]);
---
>     ss << 0 + x[i];

あと、
std::setfill() と std::hex はあらかじめ設定しておけば、以降の入力に対して有効なようだが、
std::setw() は各入力毎に必要な模様。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Wiki内検索

フリーエリア

管理人/副管理人のみ編集できます