Cで16進数から整数に変換する方法、小文字にできません!

StackOverflow https://stackoverflow.com/questions/1416571

  •  06-07-2019
  •  | 
  •  

質問

みなさん、ちょっとしたことですが、16進数から整数への変換は機能していますが、数字を小文字にする必要があります。 AからFの大文字と小文字を区別しないようにするためのアイデアはありますか?

int htoi(char f[]) {
    int  z, n;
    n = 0;

    for (z = 0; f[z] >= '0' && f[z] <= 'F'; ++z) 
        if (f[z] >= 'A' && f[z] <= 'F')
            n = 10 + 16 * n + (f[z] - 'A');
        else
            n = 16 * n + (f[z] - '0');
}

おそらく小さなことですが、a-fとA-Fを含めたいと思います。ご協力ありがとうございます!

役に立ちましたか?

解決

その方法を学ぶためにこれを行っている場合は、この投稿を無視してください。 16進数の文字列を int に変換する必要があるためにこの関数を使用している場合は、標準ライブラリを散歩する必要があります。標準関数 strtol() は文字列を変換します long に変換します。これは int (または unsigned int に移動できます)。 3番目の引数は、変換するベースです-この場合、16進数のベース16が必要です。また、ベース0を指定すると、文字列が 0x で始まる場合は16進数、 0 で始まる場合は8進数、それ以外の場合は10進数と見なされます。これは非常に便利な機能です。


編集:これに気づいたのですが、ここにいる間は、配列のインデックス付けに通常 int を使用しないでください。 C標準では、 size_t と呼ばれるタイプを定義しています。これは、配列インデックスを格納するように設計されています。通常は unsigned int または unsigned long などですが、使用できる配列またはポインターオフセットを格納するのに十分な大きさであることが保証されています。

int のみを使用する場合の問題は、理論的には、いつか誰かが INT_MAX より長い文字列を渡してから、 int はオーバーフローし、おそらくラップアラウンドし、おそらく負のインデックスを使用しているため、そうでないはずのメモリの読み取りを開始します。これは、特にこのような関数では非常にまれです。これは、 int カウンターがオーバーフローするずっと前に、返される int 値がオーバーフローするためです。ただし、 留意すべき重要なこと。

技術的に正確にするには、本当に負の値にアクセスしようとしない限り、 size_t 型変数のみを使用して配列のインデックスを作成するか、少なくとも unsigned 型のみを使用する必要があります要素(何をしているのかわからない限り、通常は悪い考えです)。ただし、ここでは大きな問題ではありません。

他のヒント

16進数を整数に変換する別の関数を作成します。

int hex_digit_to_integer(char digit) {
    if (digit >= 'A' && digit <= 'F') {
        return digit - 'A' + 10;
    } else if (digit >= 'a' && digit <= 'f') {
        return digit - 'a' + 10;
    } else if (digit >= '0' && digit <= '9') {
        return digit - '0';
    }

    return -1; // Bad input.
}

4つのケースの処理方法に注意してください。  * digit は大文字の A..F で、  * digit は小文字の a..f です。  * digit は10進数の 0..9 であり、  * digit は上記のいずれでもありません。

ここで、元の関数で新しい関数を使用します。

int htoi(char f[]) {
    int z, n;
    n = 0;

    /* Loop until we get something which isn't a digit (hex_digit_to_integer returns something < 0). */
    for (z=0; hex_digit_to_integer(f[z]) >= 0; ++z) {
        n = 16 * n + hex_digit_to_integer(f[z]);
    }
}

新しい関数がどれだけきれいに見えるかに注意してください

冒険好きなら、この魔法の関数を使うことができます(悪い入力を処理しないので、事前に確認する必要があります):

int hex_digit_to_integer(char digit) {
    return digit - (digit & 64 ? 55 : 48) & 15;
}

すべてのf [z]を専用の変数に置き換えます。 toupper(f [z])でその変数を割り当てます

NPS NSRL Bloomパッケージのコードを次に示します。

static int *hexcharvals = 0;

/** Initialization function is used solely for hex output
 */
static void nsrl_bloom_init()
{
    if(hexcharvals==0){
        /* Need to initialize this */
        int i;
        hexcharvals = calloc(sizeof(int),256);
        for(i=0;i<10;i++){
            hexcharvals['0'+i] = i;
        }
        for(i=10;i<16;i++){
            hexcharvals['A'+i-10] = i;
            hexcharvals['a'+i-10] = i;
        }
    }
}

/**
 * Convert a hex representation to binary, and return
 * the number of bits converted.
 * @param binbuf output buffer
 * @param binbuf_size size of output buffer in bytes.
 * @param hex    input buffer (in hex)
 */
int nsrl_hex2bin(unsigned char *binbuf,size_t binbuf_size,const char *hex)
{
    int bits = 0;
    if(hexcharvals==0) nsrl_bloom_init();
    while(hex[0] && hex[1] && binbuf_size>0){
        *binbuf++ = ((hexcharvals[(unsigned char)hex[0]]<<4) |
                     hexcharvals[(unsigned char)hex[1]]);
        hex  += 2;
        bits += 8;
        binbuf_size -= 1;
    }
    return bits;
}

このコードは、超高速で、大文字と小文字の両方の16進数を処理し、任意の長さの16進数文字列を処理するように設計されています。関数nsrl_hex2bin()は、バイナリバッファ、そのバッファのサイズ、および変換する16進文字列を受け取ります。実際に変換されたビット数を返します。

ああ、整数だけが必要な場合は、バイトを乗算する(エンディアンに依存しないコードの場合)か、キャストするだけです(エンディアンに依存するコードの場合)。

代わりに sscanf を試すことができます:

#include <stdio.h>

...

//NOTE: buffer overflow if f is not terminated with \0 !!
int htoi(char f[]){
  int intval = -1;
  if (EOF == sscanf(f, "%x", &intval))
    return -1; //error
  return intval;
}

2つのオプション:

スキャンを実行する前に大文字に変換します。

小文字を処理する4つのループにifを追加します。

代わりにこれを試してください:

int htoi (char f[]) {
    int  z, n;
    n = 0;
    for (z = 0; f[z] != '\0'; ++z) { 
        if (f[z] >= '0' && f[z] <= '9') {
            n = n * 16 + f[z] - '0';
        } else {
            if (f[z] >= 'A' && f[z] <= 'F') {
                n = n * 16 + f[z] - 'A' + 10;
            } else {
                if (f[z] >= 'a' && f[z] <= 'f') {
                    n = n * 16 + f[z] - 'a' + 10;
                } else {
                    break;
                }
            }
        }
    }
    return n;
}

入力をあなたと同じように扱います(ポインターを使用する傾向がありますが、初心者には理解しにくい場合があります)が、0-9、AF、afの3つの別々のケースを導入し、それぞれを適切に処理します。

実際の元のコードでは、誤った文字(「9」と「A」の間の6文字)が許可され、それらに基づいて誤った結果が生成されます。

この新しいコードは、通常、文字列の最後でループを終了するだけです。無効な16進文字を見つけると、ループから抜け出し、機能的には終了条件と同じになります。

strtol()を使用してください。これは標準のC90関数であり、ほとんどの単純な実装よりもはるかに強力です。また、dec(プレフィックスなし)、hex(0x)、oct(0から始まる)からのシームレスな変換もサポートしています。

および乗算の代わりにシフト回転を使用した実装。

int HexToDec(char *Number)
{

    unsigned int val = 0;

    int i , nibble;
    for(i = strlen( Number ) - 1; i >= 0; --i, nibble += 4)
    {
        const char hex = Number[i];
        if (hex >= '0' && hex <= '9')
            val += (hex - '0')<<nibble;
        else if (hex >= 'A' && hex <= 'F')
            val += (hex - 'A' + 10)<<nibble;
        else if (hex >= 'a' && hex <= 'f')
            val += (hex - 'a' + 10)<<nibble;
        else
            return -1;
    }
    return val;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top