我需要将四个十六进制字符的字符串解析为整数。字符出现在一个较长的字符串中,并且没有分隔符 - 我只知道它们可以找到的偏移量。十六进制字符不区分大小写。偏移量为3的示例:
"foo10a4bar" -> 4260
我正在寻找一个
的片段我对使用'sscanf'系列函数有点怀疑,但是如果有一个安全的ANSI C解决方案使用它们,可以使用它们。
答案 0 :(得分:3)
strtol
很简单,错误处理很好:
const int OFFSET = 3, LEN = 4;
char hex[LEN + 1];
int i;
for(i = 0; i < LEN && str[OFFSET + i]; i++)
{
hex[i] = str[OFFSET + i];
if(!isxdigit((unsigned char) hex[i]))
{
// signal error, return
}
}
if(i != LEN)
{
// signal error, return
}
hex[LEN] = '\0';
char *end;
int result = (int) strtol(hex, &end, 16);
if(end != hex + LEN)
{
// signal error, return
}
答案 1 :(得分:2)
这是我的尝试
#include <assert.h>
static int h2d(char c) {
int x;
switch (c) {
default: x = -1; break; /* invalid hex digit */
case '0': x = 0; break;
case '1': x = 1; break;
case '2': x = 2; break;
/* ... */
case 'E': case 'e': x = 14; break;
case 'F': case 'f': x = 15; break;
}
return x;
}
int hex4(const char *src, int offset) {
int tmp, val = 0;
tmp = h2d(*(src+offset+0)); assert(tmp >= 0); val += tmp << 12;
tmp = h2d(*(src+offset+1)); assert(tmp >= 0); val += tmp << 8;
tmp = h2d(*(src+offset+2)); assert(tmp >= 0); val += tmp << 4;
tmp = h2d(*(src+offset+3)); assert(tmp >= 0); val += tmp;
return val;
}
当然,而不是assert
使用您首选的验证方法!
你可以像这样使用它
int val = hex4("foo10a4bar", 3);
答案 2 :(得分:2)
通常最好尽可能使用标准函数,以获得简洁明了的代码:
#define HEXLEN 4
long extract_hex(const char *src, size_t offset)
{
char hex[HEXLEN + 1] = { 0 };
long val;
if (strlen(src) < offset + HEXLEN)
return -1;
memcpy(hex, src + offset, HEXLEN);
if (strspn(hex, "0123456789AaBbCcDdEeFf") < HEXLEN)
return -1;
errno = 0;
val = strtol(hex, NULL, 16);
/* Out of range - can't occur unless HEXLEN > 7 */
if (errno)
return -1;
return val;
}
答案 3 :(得分:1)
这是基于字符算术的替代方案:
int hexdigits(char *str, int ndigits)
{
int i;
int n = 0;
for (i=0; i<ndigits; ++i) {
int d = *str++ - '0';
if (d > 9 || d < 0)
d += '0' - 'A' + 10;
if (d > 15 || d < 0)
d += 'A' - 'a';
if (d > 15 || d < 0)
return -1;
n <<= 4;
n |= d;
}
return n;
}
它应该处理两种情况下的数字,并且适用于ASCII和EBCDIC。使用超过7位的数字会引发整数溢出,并且可以使用-1作为错误值,与有效转换无法区分。
只需使用添加到基本字符串的偏移量调用它:例如w = hexdigits(buf+3, 4);
表示将3个字符的建议偏移量存储到buf
中存储的字符串中。
编辑:这是一个版本较少的版本,可以保证适用于ASCII。我有理由相信它也适用于EBCDIC,但没有任何关于这种风格的文字可以证明它。
另外,我修正了一个愚蠢的疏忽,并使累加器变为int
而不是unsigned short
。它不会影响4位数的情况,但它只使用16位数而不是int
的全部容量溢出。
int hexdigits2(char *str, int ndigits)
{
int i;
int n = 0;
for (i=0; i<ndigits; ++i) {
unsigned char d = *str++ - '0';
if (d > 9)
d += '0' - 'A' + 10;
if (d > 15)
d += 'A' - 'a';
if (d > 15)
return -1;
n <<= 4;
n |= d;
}
return n;
}
用法与早期版本相同,但生成的代码可能会小一些。
答案 4 :(得分:0)
现在我自己尝试了一下,我想了一下 - 我不确定这是最好的,所以我会等一会儿,然后接受对我来说最好的答案。
val = 0;
for (i = 0; i < 4; i++) {
val <<= 4;
if (ptr[offset+i] >= '0' && ptr[offset+i] <= '9')
val += ptr[offset+i] - '0';
else if (ptr[offset+i] >= 'a' && ptr[offset+i] <= 'f')
val += (ptr[offset+i] - 'a') + 10;
else if (ptr[offset+i] >= 'A' && ptr[offset+i] <= 'F')
val += (ptr[offset+i] - 'A') + 10;
else {
/* signal error */
}
}
答案 5 :(得分:0)
/* evaluates the first containing hexval in s */
int evalonehexFromStr( const char *s, unsigned long *val )
{
while( *s )
if( 1==sscanf(s++, "%04lx", val ) )
return 1;
return 0;
}
它适用于4个十六进制数字,例如:
unsigned long result;
if( evalonehexFromStr("foo10a4bar", &result) )
printf("\nOK - %lu", result);
如果您需要其他十六进制数字大小,请将“4”替换为您的大小,或者对于任何十六进制值,请将“%lx”替换为最大MAX_ULONG的值。
答案 6 :(得分:-1)
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int offset = atoi(argv[2]);
argv[1][offset + 4] = '\0';
printf("%lu\n", strtol(argv[1] + offset, NULL, 0x10));
}
matt@stanley:$ make small_hex_converter cc small_hex_converter.c -o small_hex_converter matt@stanley:$ ./small_hex_converter f0010a4bar 3 4260