我需要一些帮助来将字符串切割成一对字符,然后将其转换为 HEX 格式。
例如。字符 *ADDRESS = "0011AABB"; 我希望将上述地址拆分为“00”、“11”、“AA”和“BB”,然后拆分将其转换为 0x00、0x11、0xAA 和 0xBB,这些地址将存储在无符号字符中。
谢谢
我需要一些帮助来将字符串切割成一对字符,然后将其转换为 HEX 格式。
例如。字符 *ADDRESS = "0011AABB"; 我希望将上述地址拆分为“00”、“11”、“AA”和“BB”,然后拆分将其转换为 0x00、0x11、0xAA 和 0xBB,这些地址将存储在无符号字符中。
谢谢
您建议您的地址字符串是 type char *
,但我假设您想要一个保证不丢弃它们的解决方案,即将它们作为 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 字符十六进制数字转换为编码的 32 位无符号整数,然后以高字节优先顺序获取组成此无符号整数的 4 个无符号字符字节来实现您的目标. uint32_t
只需调用 . 即可将
十六进制数字转换为 a strtoul
。然后uint32_t
以高字节优先顺序获取 unsigned char 字节只是知道这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 构建和测试