0

文字列を文字のペアに切り取り、それを HEX 形式に変換する際に助けが必要です。

例えば。char *ADDRESS = "0011AABB"; 上記のアドレスを「00」、「11」、「AA」、「BB」に分割し、その後分割して0x00、0x11、0xAA、0xBBに変換し、unsigned charに格納します。

ありがとう

4

1 に答える 1

1

あなたはアドレス文字列が typechar *であることを示唆していますが、それらを破棄しないことを保証する解決策、つまりそれらを type として受け取る解決策が必要だと思いますchar const *

また、例のように、それらが表すことができるアドレスは 32 ビットであると仮定しますchar *ADDRESS = "0011AABB"

その場合、あなたが求めていることを明白な方法で正確に実行するソリューションは次のとおりです。

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#define ADDRESS_BYTES 4 // Bytes in an address

/* Convert a hex numeral encoding an address to the unsigned chars that it 
    encodes

    `addr_str` - in: a hex numeral encoding an address
    `bytes` - out: The unsigned char bytes of the address, high-byte first.

    return - The number of bytes output: ADDRESS_BYTES if `addr_str` is a 
        valid hex numeral, otherwise 0.
*/  
unsigned address_bytes(char const *addr_str, unsigned char bytes[ADDRESS_BYTES])
{
    char buf[3] = {0}; // 3-bytes of 0-filled working space.
    char *endp;
    unsigned i = 0;
    unsigned j = 0;
    assert(strlen(addr_str) == 2 * ADDRESS_BYTES); // Insist on 8-char string
    for (   ;i < 2 * ADDRESS_BYTES; ++j) { // Take chars 2 at a time
        buf[i % 2] = addr_str[i]; ++i; // Next char to buf[0]
        buf[i % 2] = addr_str[i]; ++i; // Next + 1 char to buf[1]
        // Convert buffer from hex numeral to unsigned char in next byte.
        bytes[j] = (unsigned char)strtoul(buf,&endp,16);
        if (*endp) { // Check for invalid hex. 
            return 0; // Failure
        }
    }
    return j; // = 4
}

// A test program...

#include <stdio.h>

int main(void)
{
    unsigned char bytes[ADDRESS_BYTES];
    char const * address = "0011AABB";
    unsigned done_bytes = address_bytes(address,bytes);
    printf("The %d valid address bytes are (hex):",done_bytes);
    unsigned i = 0;
    for (   ;i < done_bytes; ++i) {
        printf(" %02x",(unsigned)bytes[i]);
    }
    putchar('\n');
    return 0;
}

ただし、正確に求めるものは効率的なソリューションではありません。32 ビット アドレスをエンコードする 8 文字の 16 進数をエンコードされた 32 ビット符号なし整数に変換し、この符号なし整数を構成する 4 つの符号なし char バイトを上位バイトから順に取得するだけで、目的を達成できます。 . 16 進数を に変換するにはuint32_t、 を 1 回呼び出すだけ strtoulです。次に、この unsigned char バイトをuint32_t上位バイトから順に取得することは、それuint32_tがビッグ エンディアンかリトル エンディアンかを知るだけの問題です。したがって、より良い解決策は次のとおりです。

#include <assert.h>
#include <stdlib.h>
#include <string.h> 
#include <inttypes.h>

unsigned address_bytes(char const *address, unsigned char bytes[ADDRESS_BYTES])
{
    union {
        uint32_t i;
        char c[ADDRESS_BYTES];
    } endian_tester = {0x01020304};

    int big_endian = endian_tester.c[0] == 1; 
    uint32_t addr = 1;
    char *endp;
    assert(strlen(address) == 2 * ADDRESS_BYTES);
    addr = (uint32_t)strtoul(address,&endp,16);
    if (*endp) {
        return 0;
    }
    endp = (char *)&addr;
    if (big_endian) {
        // The least significant byte is highest in memory
        bytes[0] = endp[0];
        bytes[1] = endp[1];
        bytes[2] = endp[2];
        bytes[3] = endp[3];
    } else {
        // The least significant byte is lowest in memory
        bytes[0] = endp[3];
        bytes[1] = endp[2];
        bytes[2] = endp[1];
        bytes[3] = endp[0];
    }
    return ADDRESS_BYTES;
}

また、アドレス文字列が ASCII でエンコードされているという移植性のない仮定 を行うことができ、その意思がある場合は、strtoul完全に呼び出すことを避け、ASCII 照合での文字の位置を使用して、入力文字から出力バイトを直接計算できます。エンコードする unsigned char 値を取得するシーケンス:

#include <assert.h>
#include <string.h> 
#include <ctype.h>

unsigned address_bytes(char const *address, unsigned char bytes[ADDRESS_BYTES])
{
    unsigned i = 0;
    unsigned j = 0;
    assert(strlen(address) == 2 * ADDRESS_BYTES);
    for (   ; i < 2 * ADDRESS_BYTES; ++i,++j) {
        // First character of a pair..
        if (isdigit(address[i])) {
            // A decimal digit encodes its ASCII value - '0'
            bytes[j] = address[i] - '0';
        } else if (isxdigit(address[i])) {
            // A hex digit encodes 10 + its ASCII value - 'A'
            bytes[j] = 10 + address[i] - 'A';
        } else {
            return 0; // Invalid hex
        }
        ++i; // Second character of a pair...
        bytes[j] <<= 4; // Shift the 1st character's value 1 nibble high
        // OR the 2nd character's value into the low nibble of the byte...
        if (isdigit(address[i])) {
            bytes[j] |= address[i] - '0';
        } else if (isxdigit(address[i])) {
            bytes[j] |= 10 + address[i] - 'A';
        } else {
            return 0; // Invalid hex
        }
    }
    return ADDRESS_BYTES;
}

それが重要な場合、最後が最速かもしれません。

GCC 4.7.2 および clang 3.2 でビルドおよびテスト済み

于 2013-05-09T10:26:22.363 に答える