将十六进制表示的数字字符串转换为实际数值

3

我有一个这样的字符串:

"00c4"

我需要将它转换为字面值所表示的数值:

0x00c4

我该怎么做?
6个回答

3

stdlib.h中的 strtol 函数(或者无符号长整型的 strtoul 函数),可以帮助您将一个字符串按指定进制转换为长整型。因此,以下代码可以实现这个功能:

char *s = "00c4";
char *e;
long int i = strtol (s, &e, 16);
// Check that *e == '\0' assuming your string should ONLY
//    contain hex digits.
// Also check errno == 0.
// You can also just use NULL instead of &e if you're sure of the input.

在我看来,你只需要检查 *e == '\0',检查 e == s+strlen(s) 就有点过了。 - nothrow
strtol完成了任务。谢谢! - Gerstmann
好观点,@Yossarian。无论您将此代码用于仅包含十六进制数字的字符串还是允许空格以及零字节等内容,都可能超出问题的范围。我应该把它留出来,因为这只是一种方法,根据字符串格式可能是错误的方法。我会采纳您的评论,因为这是一个好建议。 - paxdiablo
1
@ExplodingRat,要注意高位为1的数字(任何以8f开头的数字),它们可能会被扩展成负数。使用strtoul可能更安全。 - paxdiablo

2
您可以参考C++ FAQ中的stringify示例进行调整:链接在此
#include <iostream>
#include <sstream>
#include <stdexcept>

class bad_conversion : public std::runtime_error
{
public:
  bad_conversion(std::string const& s)
    : std::runtime_error(s)
  { }
};

template<typename T>
inline void convert_from_hex_string(std::string const& s, T& x,
  bool failIfLeftoverChars = true)
{
  std::istringstream i(s);
  char c;
  if (!(i >> std::hex >> x) || (failIfLeftoverChars && i.get(c)))
    throw ::bad_conversion(s);
}

int main(int argc, char* argv[])
{
  std::string blah = "00c4";
  int input;
  ::convert_from_hex_string(blah, input);
  std::cout << std::hex << input << "\n";
  return 0;
}

有人知道如何通用地指定一个可以接受std::hex的参数吗?这样就可以得到一个更通用的函数。std::hex的函数签名看起来有点难看,使用也不明显。我也不能立即想出空默认值会是什么样子。 - Merlyn Morgan-Graham
你可能想将输入行更改为 i >> std::hex >> x >> std::ws,这样尾随的空格就不会触发异常了。 - sbi
我认为你需要将一个函数指针 std::ios_base& (*)(std::ios_base&) 作为参数。 - sbi
@sbi:只有在我将“failIfLeftoverChars”设置为true时(就像我在这里的示例中一样),尾随空格才会触发异常。我刚刚测试了一下。 - Merlyn Morgan-Graham
是的,我看到了。不过,即使其他字符不允许,尾随空格通常也是允许的。另一个想法是将 failIfLeftoverChars 设为 enum 并允许第三个选项。 - sbi

2
#include <stdio.h>

int main()
{
        const char *str = "0x00c4";
        int i = 0;
        sscanf(str, "%x", &i);
        printf("%d = 0x%x\n", i, i);
        return 0;
}

当使用%x时,输入字符串无需以0x为前缀。如果您使用%i而不是%x,它将接受十进制、十六进制或八进制输入,其中十六进制输入必须以0x为前缀,八进制则以0为前缀。此外,考虑到C++标签,可以提出使用<sstream>的类似解决方案。 - Clifford
如果我将"blah"作为str传递给sscanf()会发生什么? - sbi
你应该检查 sscanf 的返回值,它会返回成功转换的数量。 - nir

1
std::string val ="00c4";
uint16_t out;
if( (std::istringstream(val)>>std::hex>>out).fail() )
{ /*error*/ }

1

实际上并不存在所谓的“实际十六进制值”。一旦你进入本地数据类型,你就处于二进制状态。从十六进制字符串转换到二进制是在上面讨论过的。将其显示为十六进制输出也是如此。但它并不是一个“实际的十六进制值”。它只是二进制。


0
int val_from_hex(char *hex_string) {
    char *c = hex_string;
    int val = 0;
    while(*c) {
        val <<= 4;
        if(*c >= '0' && *c <= '9')
            val += *c - '0';
        else if(*c >= 'a' && *c <= 'f')
            val += *c - 'a' + 10;
        c++;
    }
    return val;
}

它是否涵盖了从'A'到'F'的内容? - Chubsdad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接