1

const char*16進値を含む8文字の配列(より大きな文字列の一部である可能性があります)を指す、があります。これらの文字を4の配列に変換する関数が必要ですuint8_t。ここで、ソース配列の最初の2文字が、ターゲット配列の最初の要素になります。たとえば、私がこれを持っている場合

const char* s = "FA0BD6E4";

に変換してほしい

uint8_t i[4] = {0xFA, 0x0B, 0xD6, 0xE4};

現在、私はこれらの機能を持っています:

inline constexpr uint8_t HexChar2UInt8(char h) noexcept
{
    return static_cast<uint8_t>((h & 0xF) + (((h & 0x40) >> 3) | ((h & 0x40) >> 6)));
}

inline constexpr uint8_t HexChars2UInt8(char h0, char h1) noexcept
{
    return (HexChar2UInt8(h0) << 4) | HexChar2UInt8(h1);
}

inline constexpr std::array<uint8_t, 4> HexStr2UInt8(const char* in) noexcept
{
    return {{
        HexChars2UInt8(in[0], in[1]),
        HexChars2UInt8(in[2], in[3]),
        HexChars2UInt8(in[4], in[5]),
        HexChars2UInt8(in[6], in[7])
    }};
}

これが私がそれをどこから呼んだかです:

const char* s = ...; // the source string
std::array<uint8_t, 4> a; // I need to place the resulting value in this array
a = HexStr2UInt8(s); // the function call does not have to look like this

私が疑問に思っているのは、これを行うためのより効率的な(そしてポータブルな)方法はありますか?たとえば、返すのstd::arrayは良いことですか、それともdstポインタを渡す必要がありますHexChars2UInt8か?または、私の機能を改善する他の方法はありますか?

私がこれを求めている主な理由は、ある時点でこれを最適化する必要がある可能性があり、将来API(関数プロトタイプ)が変更された場合に問題が発生するためです。

4

3 に答える 3

2

HexChar2Uint8は同時に8文字にアクセスできるため、並列処理を追加できます。アラインされていない64ビット値を8文字ずつ1つずつロードする(そして変換関数を呼び出す)方がおそらく速いでしょう。

hexChar2Uints(uint8_t *ptr, uint64_t *result)  // make result aligned to qword
{
  uint64_t d=*(uint64_t*)ptr;
  uint64_t hi = (d>>6) & 0x0101010101010101;
  d &= 0x0f0f0f0f0f0f0f0f;
  *result = d+(hi*9);  // let compiler decide the fastest method
}

最後の段階は、OPが提案したように、変更された「文字列」から読み取るだけで実行する必要があります。

for (n=0;n<4;n++) arr[n]=(tmp[2*n]<<4) | tmp[2*n+1];

これを大幅に高速化できる可能性はわずかです。この<< 4演算はhexChar2Uintsに注入して並列化することもできますが、4回未満の算術演算で実行できるとは思えません。

于 2012-12-27T14:49:49.493 に答える
0

最も効率的な、つまり変換を行うための最速の方法は、おそらく2文字の可能なペアごとに65536値のテーブルを設定し、それらの変換を有効なものに格納することです。

それらをunsignedcharsとして保存すると、エラーをキャッチできなくなるため、有効な入力が得られることを期待する必要があります。値の型をunsignedcharよりも大きい値として格納すると、ある種の「エラー」値を使用できますが、取得したかどうかを確認するのはオーバーヘッドになります。(余分な65536バイトはおそらくそうではありません)。

あなたが書いたものはおそらく十分に効率的です。もちろん、もう一度、無効な入力をチェックしていないので、とにかく結果が得られます。

あなたがあなたのものを保つならば、私は変わるかもしれません:

((h & 0x40) >> 3) | ((h & 0x40) >> 6)

これは代わりのようです

( (h & 0x40) ? 10 : 0 )

私の表現があなたの表現よりも効率が悪く、意図がより明確であることがわかりません。(0xA16進数を主張する場合は、10ではなく使用してください)

于 2012-12-27T14:20:06.380 に答える
-2

可能なアプローチはいくつかあります。最も単純で移植性の高い方法は、文字を2文字 std::stringに分割し、それぞれを使用してを初期化std::istringstreamし、正しいフォーマットフラグを設定し、そこから値を読み取ることです。やや効率的な解決策は、単一の文字列を作成し、個々の値を区切るために空白を挿入しstd::istringstream、次のように1つだけ使用することです。

std::vector<uint8_t>
convert4UChars( std::string const& in )
{
    assert( in.size() >= 8 );
    std::string tmp( in.begin(), in.begin() + 8 );
    int i = tmp.size();
    while ( i > 2 ) {
        i -= 2;
        tmp.insert( i, 1, ' ');
    }
    std::istringstream s(tmp);
    s.setf( std::ios_base::hex, std::ios_base::basefield );
    std::vector<int> results( 4 );
    s >> results[0] >> results[1] >> results[2] >> results[3];
    if ( !s ) {
        //  error...
    }
    return std::vector<uint8_t>( results.begin(), results.end() );
}

本当に手作業で行いたい場合は、別の方法として、各文字でインデックス付けされた256エントリのテーブルを作成し、それを使用します。

class HexValueTable
{
    std::array<uint_t, 256> myValues;
public:
    HexValueTable()
    {
        std::fill( myValues.begin(), myValues.end(), -1 );
        for ( int i = '0'; i <= '9'; ++ i ) {
            myValues[ i ] = i - '0';
        }
        for ( int i = 'a'; i <= 'f'; ++ i ) {
            myValues[ i ] = i - 'a' + 10;
        }
        for ( int i = 'A'; i <= 'A'; ++ i ) {
            myValues[ i ] = i - 'a' + 10;
        }
    }
    uint8_t operator[]( char ch ) const
    {
        uint8_t results = myValues[static_cast<unsigned char>( ch )];
        if ( results == static_cast<unsigned char>( -1 ) ) {
            //  error, throw some exceptions...
        }
        return results;
    }
};

std::array<uint8_t, 4>
convert4UChars( std::string const& in )
{
    static HexValueTable const hexValues;
    assert( in.size() >= 8 );
    std::array<uint8_t, 4> results;
    std::string::const_iterator source = in.begin();
    for ( int i = 0; i < 4; ++ i ) {
        results[i] = (hexValues[*source ++]) << 4;
        results[i] |= hexValues[*source ++];
    }
    return results;
}
于 2012-12-27T14:41:41.390 に答える