scrap book

プログラミングとか

自前ヘキサダンプ関数

バイナリデータをバイナリエディタ風というかnetstat風というかそんな感じに16進数で表示する関数。実装はC++11。やりたかったことはできた気がするけどソースコードは汚い。

ソースコード
#include <ctype.h>
#include <string>
#include <iomanip>
#include <sstream>
#include <iostream>

static std::string GetDumpedString(
        void* targetData, int targetDataSize,
        bool showHead = true, bool showChar = true)
{
    unsigned char* data = static_cast<unsigned char*>(targetData);

    std::stringstream ssDump;
    std::stringstream ssHead;
    std::stringstream ssLine;
    std::stringstream ssChar;

    ssLine.width( 2 );
    ssLine.fill( '0' );
    ssLine.flags( std::ios::hex | std::ios::uppercase );

    for( int i = 0; i < targetDataSize; i++ )
    {
        if( showHead && ( i % 16 == 0 ) )
        {
            ssHead << std::setw(8) << std::setfill('0')
                   << std::hex
                   << i << ": " << std::flush;

            ssLine << ssHead.str();
        }

        ssLine << (int)data[i] << ' ';

        ssChar << ((isprint(data[i]) != 0) ? (char)data[i] : '.');

        if( (i+1) % 16 == 0 )
        {
            if( showChar )
            {
                ssLine << "    " << ssChar.str();
            }
            ssLine << std::endl;
            ssDump << ssLine.str();

            ssHead.str("");
            ssHead.clear(std::stringstream::goodbit);
            ssLine.str("");
            ssLine.clear(std::stringstream::goodbit);
            ssChar.str("");
            ssChar.clear(std::stringstream::goodbit);
        }
    }
    if( ssLine.str().size() > 0 )
    {
        int spaceSize = 3*16 + (showHead ? 10 : 0) + (showChar ? 4 : 0) - ssLine.str().size();
        ssLine << std::string(spaceSize, ' ') << ssChar.str() << std::endl;
        ssDump << ssLine.str();
    }


    return ssDump.str();
}

int main(void)
{
    using namespace std;

    cout << "          00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" << endl;

    string str = "abcdefghijklmnopqrstuvwxyz"
                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                 "01234567890";
    cout << GetDumpedString( (char*)str.data(), str.size() ) << endl;


    return 0;
}
結果
          00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000: 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70     abcdefghijklmnop
00000010: 71 72 73 74 75 76 77 78 79 7A 41 42 43 44 45 46     qrstuvwxyzABCDEF
00000020: 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56     GHIJKLMNOPQRSTUV
00000030: 57 58 59 5A 30 31 32 33 34 35 36 37 38 39 30        WXYZ01234567890

vector<string>をexecv()に渡す

掲題のコード。正直いまいち分かってない。

ソース
#include <unistd.h>
#include <vector>
#include <string>

using namespace std;

int main(void)
{
    vector<string> argList = { string("/bin/echo"), string("a"), string("b") };
    const char **argv = new const char*[argList.size()+1];


    for( size_t i = 0; i < argList.size(); i++ )
    {
        argv[i] = argList.at(i).c_str();
    }
    argv[argList.size()] = NULL;

    execv( argv[0], (char**)argv );

    delete argv;


    return 0;
}

boostでiniファイルを読み込んでmapに詰め込む

いつも地味に面倒なiniからの読み込みを簡単にするためにboost::property_treeでiniファイルを読み込んでmap<string,string>に詰め込むサンプル。

読み込むiniファイル(sample.ini)
[sectionA]
key1        = val1

[section B]
spaced key  = spaced value

[section C]         # comment
key1        = 1     # duped name
key2        = あ    ; japanee

# comment
; comment
ソース(おためし)

まずは試しに表示するソースコード。普通にget_value()すると'='以降すべて取得できてしまうので、特定の文字以降をコメントとして扱いたい場合はsplit()してtrim()してあげる必要があるみたい。

#include <iostream>
#include <string>
#include <vector>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/algorithm/string.hpp>

void printIni2(const char* filepath)
{
    using boost::property_tree::ptree;
    ptree pt;

    read_ini( filepath, pt, std::locale("japanese") );

    std::vector<std::string> valStrList;
    for (auto& section : pt)
    {
        std::cout << '[' << section.first << "]" << std::endl;
        for (auto& key : section.second)
        {
            std::string valStr = key.second.get_value<std::string>();
            boost::split(valStrList, valStr, boost::is_any_of("#;"));

            std::cout << key.first << "=" << boost::algorithm::trim_copy(valStrList.at(0)) << std::endl;
        }
    }
}

void printIni(const char* filepath)
{
    using boost::property_tree::ptree;
    ptree pt;

    read_ini( filepath, pt, std::locale("japanese") );

    for (auto& section : pt)
    {
        // print part of "[section name]"
        std::cout << '[' << section.first << "]" << std::endl;

        // print part of "key = value"
        for (auto& key : section.second)
        {
            std::cout << key.first << "=" << key.second.get_value<std::string>() << std::endl;
        }
    }
}

int main(int argc, char* argv[])
{
    printIni("sample.ini");

    std::cout << "--------------------------------" << std::endl;
    printIni2("sample.ini");

    return 0;
}
結果
[sectionA]
key1=val1
[section B]
spaced key=spaced value
[section C]
key1=1     # duped name
key2=あ    ; japanee
--------------------------------
[sectionA]
key1=val1
[section B]
spaced key=spaced value
[section C]
key1=1
key2=あ
ソース(本題)

本題のソースコード

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>

void ini2map(const char* filepath, std::map<std::string, std::string>& iniMap)
{
    using boost::property_tree::ptree;
    ptree pt;

    read_ini( filepath, pt, std::locale("japanese") );

    std::vector<std::string> valStrList;
    for (auto& section : pt)
    {
        std::string sectionName = section.first;

        for (auto& key : section.second)
        {
            std::string valStr = key.second.get_value<std::string>();
            boost::split(valStrList, valStr, boost::is_any_of("#;"));

            std::string keyName = key.first;
            std::string val = boost::algorithm::trim_copy(valStrList.at(0));

            std::cout << keyName << "=" << val << std::endl;

            iniMap[sectionName+"."+keyName] = val;
        }
    }
}

int main(int argc, char* argv[])
{
    std::map<std::string, std::string> iniMap;
    ini2map("sample.ini", iniMap);
    std::cout << iniMap.size() << std::endl;

    // print
    for( auto kvp : iniMap )
    {
        std::cout << kvp.first << "=" << kvp.second << std::endl;
    }
    // get value as int
    std::cout << boost::lexical_cast<int>(iniMap.at("section C.key1")) << std::endl;
    // get value (failure)
    try
    {
        std::string valStr = iniMap.at(" undefined key ");
    }
    catch(std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }

    return 0;
}
結果
key1=val1
spaced key=spaced value
key1=1
key2=あ
4
section B.spaced key=spaced value
section C.key1=1
section C.key2=あ
sectionA.key1=val1
1
map::at
ソース(おまけ)

ぶっちゃけ以下のようなコードで取得できるだろうけど、プロパティツリーを意識しないようにしたかった。あとこの場合は行内コメントできない。

ptree pt;
read_ini("ini file", pt);
string strValue = pt.get<string>("[section].item");
int intValue = pt.get<int>("[section].item");


メモ:

  • forループの部分がこれで回るのはptreeが「map< string, map> >」みたいな入れ子構造になっているかららしい。
    • セクションがない項目は1階層目に入るので今回のコードだとうまく扱えない。
  • せっかくなのでread_iniのロケールにjapanese指定してみたけど、実は指定しなくてもSJISのファイル読めた。逆にjapanese指定してもutf-8のファイル読めた。この辺はよくわからない。
  • 環境:c++11 + boost 1.53


参考:

std::queue::pop()はデストラクタがあれば呼び出す

std::queue::pop()はデストラクタを呼び出す。しかしポインタ型を格納した場合は例外。
ポインタ型そのものがデストラクタを持っていないため、らしい。
逆に実体をpop()するとスコープ抜けたときとあわせて2回呼ばれることになる。

code.cpp

#include <queue>
#include <iostream>

using namespace std;

class animal {
    string kind;
public:
    animal(string kind) {
        this->kind = kind;
        cout << "animal ctor : " << kind << endl;
    }
    ~animal() {
        cout << "animal dtor : " << kind << endl;
    }
};

int main(void)
{
    queue<animal*> q;
    q.push( new animal("dog") );
    auto dog = q.front();
    q.pop();
    delete dog;


    queue<animal> q2;
    animal cat = animal("cat");
    q2.push( cat );
    q2.pop();
    // 1st dtor call by pop()

    cout << "popd" << endl;
    // 2nd dtor call by cat


    return 0;
}


result

dog ctor : pochi
dog dtor : pochi
cat ctor : tama
cat dtor : tama
popd
cat dtor : tama


参考

null文字のないchar[]の変換メモ

null文字のないchar[]の変換メモ。面倒

code.cpp

#include <iostream>
#include <sstream>
#include <iomanip>
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace boost;


// print 'lexical_cast'ed cstr
void casttest( const char* cstr )
{
    cout << "[" << cstr << "]" << endl;

    try
    {
        cout << "    ->" << lexical_cast<int>(cstr) << endl;
    }
    catch(std::exception& e)
    {
        cout << "    ->" << e.what() << endl;
    }
}


// int -> char[]
void int2zerochars(int val, char* cstr, size_t size)
{
    stringstream ss;
    ss.fill('0');
    ss << setw(size) << val;

    ss.str().copy(cstr, size);
}

// string -> char[]
void str2chars(string str, char* cstr, size_t size)
{
    // string::copy(dst, size, start_pos = 0);

    str.copy(cstr, size, 0);
}


// char[] -> string
string chars2str(char chars[], size_t size)
{
    stringstream ss;

    for(size_t i = 0; i < size; i++)
    {
        ss << chars[i];
    }

    return ss.str();
}


int main(void)
{
    char src[2] = { '9', '2' };

    cout << chars2str( src, sizeof(src) ) << endl;

    int val = lexical_cast<int>(chars2str( src, sizeof(src) ));
    cout << val << endl;


    //------------------------------------------------------
    casttest(" ");
    casttest("");
    casttest("a");
    casttest("0xDD");
    casttest("000");
    casttest("010");
    casttest("-1");
    casttest("--1");
    casttest("1-1");


    //------------------------------------------------------
    char dst[4] = { 'x', 'x', 'x', 'x' };

    string abc("abc");
    string defg("defg");
    string hijkl("hijkl");

    // 3characters (size-1)
    str2chars(abc, dst, sizeof(dst));
    cout << dst << endl;
    for(size_t i=0; i<sizeof(dst); i++){ cout<<"  "<<i<<":"<<dst[i]; cout<<endl; }

    // 4characters (size)
    str2chars(defg, dst, sizeof(dst));
    cout << dst << endl;
    for(size_t i=0; i<sizeof(dst); i++){ cout<<"  "<<i<<":"<<dst[i]; cout<<endl; }

    // 5characters (size+1)
    str2chars(hijkl, dst, sizeof(dst));
    cout << dst << endl;
    for(size_t i=0; i<sizeof(dst); i++){ cout<<"  "<<i<<":"<<dst[i]; cout<<endl; }

    //------------------------------------------------------
    char xxxx[4] = { 'x', 'x', 'x', 'x' };

    int2zerochars( 2, xxxx, sizeof(xxxx) );
    cout << xxxx << endl;  cout.flush() << endl;

    int2zerochars( 888, xxxx, sizeof(xxxx) );
    cout << xxxx << endl;  cout.flush() << endl;

    int2zerochars( 9999, xxxx, sizeof(xxxx) );
    cout << xxxx << endl;  cout.flush() << endl;

    int2zerochars( 77777, xxxx, sizeof(xxxx) );
    cout << xxxx << endl;  cout.flush() << endl;

    cout << 9 << endl;

    return 0;
}


result

92
92
[ ]
    ->bad lexical cast: source type value could not be interpreted as target
[]
    ->bad lexical cast: source type value could not be interpreted as target
[a]
    ->bad lexical cast: source type value could not be interpreted as target
[0xDD]
    ->bad lexical cast: source type value could not be interpreted as target
[000]
    ->0
[010]
    ->10
[-1]
    ->-1
[--1]
    ->bad lexical cast: source type value could not be interpreted as target
[1-1]
    ->bad lexical cast: source type value could not be interpreted as target
abcx
  0:a
  1:b
  2:c
  3:x
defg
  0:d
  1:e
  2:f
  3:g
hijk
  0:h
  1:i
  2:j
  3:k
0002<

0888<

9999<

7777<

9