我需要一个函数将32位或24位带符号(二进制补码)十六进制字符串转换为long int。需要在32位和64位机器上工作(无论长int的大小),无论机器是否是双补机,都需要工作。
SOLUTION:
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;
}
答案 0 :(得分:5)
对于24位字符串:
解析十六进制字符串时,标准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位,因此您可以使用它。
E.g。
long int ParseHexStr(const char *in, int bits)
{
char* endptr;
long long int result;
result = strtoll(in, &endptr, 16);
/*
** TODO - error checking, e.g. 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;
}
答案 1 :(得分:1)
我们有一个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;
}
答案 2 :(得分:1)
这种比较错误:if (toupper (string[0]) == 'F')
您需要使用MSB集对任何值进行符号扩展,例如:
if(strchr("89ABCDEF", toupper(string[0])) != NULL)
答案 3 :(得分:1)
有没有理由不能将strtol用于基数16?
答案 4 :(得分:0)
if (toupper (string[0]) == 'F')
{
return (result | 0xFF000000);
}
这将生成带有正确符号的数字。
if (toupper (string[0]) == 'F')
{
return ( ~(result | 0xFF000000) + 1);
}
这将始终产生积极的结果