签名hex字符串到long int函数
我需要一个函数将32位或24位带符号(二进制补码)hex字符串转换为long int。 需要在32位和64位机器上工作(无论长度大小如何),无论机器是否是双补机,都需要工作。
解:
long int hex2li (char hexStr[], int signedHex) { int bits = strlen (hexStr) * 4; char *pEnd; long long int result = strtoll (hexStr, &pEnd, 16); if (pEnd[0] == '\0') { if (signedHex) { if (result >= (1LL << (bits - 1))) result -= (1LL << bits); } return (long int) result; } return LONG_MIN; }
对于24位字符串:
解析hex字符串时,标准的strtol
函数会将其读取为0 -> 2^24 - 1
范围内的无符号值。
范围0 -> 2^23 - 1
是正确的,但是范围2^23 -> 2^24 - 1
需要映射到-2^23 -> -1
这是一个简单的减法,可以按如下方式执行。
if (result >= (1L << 23)) result -= (1L << 24);
要使用相同的技术转换32位字符串,必须使用中间类型,该中间类型可以表示带符号类型的完整32位无符号整数,以执行减法。 long long int
保证为64位,因此您可以使用它。
例如
long int ParseHexStr(const char *in, int bits) { char* endptr; long long int result; result = strtoll(in, &endptr, 16); /* ** TODO - error checking, eg check endptr != in ** Also check for range errors, signalled by LLONG_MIN ** LLONG_MAX and a errno == ERANGE. */ if (result >= (1LL << (bits - 1)) result -= (1LL << bits); return result; }
我们有一个SIGN_EXTEND
宏,看起来像:
#define SIGN_EXTEND(X, SignBit, Type) \ (((Type) ((X) << (8 * sizeof(Type) - (SignBit) - 1))) >> \ (8 * sizeof(Type) - (SignBit) - 1))
当符号位置位时,它依赖于>>
运算符1 – 填充输入。 使用它像:
SIGN_EXTEND(0x89abcd, 23, int32_t);
对于您的问题,您可以使用:
long int hex2li (char string[]) { char *pEnd; long int result = SIGN_EXTEND(strtol (string, &pEnd, 16), 23, long int); if(pEnd[0] == '\0') return result; return LONG_MIN; }
这种比较是错误的: if (toupper (string[0]) == 'F')
您需要使用MSB集对任何值进行符号扩展,例如:
if(strchr("89ABCDEF", toupper(string[0])) != NULL)
有没有理由不能将strtol与16号基数一起使用?
if (toupper (string[0]) == 'F') { return (result | 0xFF000000); }
这将生成带有正确符号的数字。
if (toupper (string[0]) == 'F') { return ( ~(result | 0xFF000000) + 1); }
这将永远产生积极的结果