您建议您的地址字符串类型为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 构建和测试