【问题标题】:Cut string into parts of 2 charactered string and then to hex format (char * to unsigned char) in C将字符串切割成 2 个字符的字符串的一部分,然后在 C 中以十六进制格式(char * 到 unsigned char)
【发布时间】:2012-11-17 02:30:03
【问题描述】:

我需要一些帮助来将字符串切割成一对字符,然后将其转换为 HEX 格式。

例如。字符 *ADDRESS = "0011AABB"; 我希望将上述地址拆分为“00”、“11”、“AA”和“BB”,然后将其拆分为 0x00、0x11、0xAA 和 0xBB,它们将存储在无符号字符中。

谢谢

【问题讨论】:

  • 你用什么语言做这个? C ?
  • 是的,编程语言是C。

标签: c string visual-studio char cut


【解决方案1】:

您建议您的地址字符串类型为char *,但我假设您 想要一种保证不破坏它们的解决方案,即带走它们的解决方案 输入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;
}

但是,您所要求的并不是一个有效的解决方案。 您可以通过简单地转换一个 8 字符的十六进制数字编码来实现您的目标 将 32 位地址转换为编码的 32 位无符号整数,然后得到 4 个无符号字符字节,按高字节优先顺序组成此无符号整数。 只需一次调用即可将十六进制数字转换为uint32_t strtoul。然后得到这个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 整理序列中的位置 获取它们编码的无符号字符值:

#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 构建和测试

【讨论】:

  • 谢谢你,达到目的!
猜你喜欢
  • 2015-05-22
  • 2015-05-22
  • 2018-09-14
  • 1970-01-01
  • 2016-09-15
  • 2015-04-14
  • 2010-09-09
  • 1970-01-01
  • 2018-03-27
相关资源
最近更新 更多