7

我正在从文件中读取一个字符串,所以它是char数组的形式。我需要对字符串进行标记并将每个char数组标记保存为数组中的uint8_t十六进制值。

char* starting = "001122AABBCC";
// ...
uint8_t[] ending = {0x00,0x11,0x22,0xAA,0xBB,0xCC}

我怎样才能从 转换startingending?谢谢。

4

9 回答 9

2

这是一个完整的工作程序。它基于 Rob I 的解决方案,但修复了几个已测试工作的问题。

#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <iostream>


const char* starting = "001122AABBCC";
int main() 
{
    std::string starting_str = starting;
    std::vector<unsigned char> ending;
    ending.reserve( starting_str.size());
    for (int i = 0 ; i < starting_str.length() ; i+=2) {
        std::string pair = starting_str.substr( i, 2 );
        ending.push_back(::strtol( pair.c_str(), 0, 16 ));
    }

    for(int i=0; i<ending.size(); ++i) {
        printf("0x%X\n", ending[i]);
    }

}
于 2014-08-18T17:52:34.630 回答
1

strtoul会将您选择的任何基数的文本转换为字节。您必须做一些工作才能将输入字符串切成单个数字,或者您可以一次转换 32 位或 64 位。

ps uint8_t[] ending = {0x00,0x11,0x22,0xAA,0xBB,0xCC}

没有任何意义,您不是将数据存储在 uint8 中作为“十六进制”,而是存储字节,这取决于您(或您的调试器)如何解释二进制数据

于 2012-07-26T20:52:42.813 回答
1

使用 C++11,您可以使用std::stoi

std::vector<uint8_t> convert(const std::string& s)
{
    if (s.size() % 2 != 0) {
        throw std::runtime_error("Bad size argument");
    }
    std::vector<uint8_t> res;
    res.reserve(s.size() / 2);
    for (std::size_t i = 0, size = s.size(); i != size; i += 2) {
        std::size_t pos = 0;
        res.push_back(std::stoi(s.substr(i, 2), &pos, 16));
        if (pos != 2) {
            throw std::runtime_error("bad character in argument");
        }
    }
    return res;
}

活生生的例子

于 2014-08-20T09:07:36.513 回答
1

我认为任何规范的答案(wrt the bounty notes)都会涉及解决方案中的一些不同阶段:

  • 错误检查有效输入
    • 长度检查和
    • 数据内容检查
  • 元素转换
  • 输出创建

鉴于这种转换的有用性,解决方案可能应该包括一些灵活性,即所使用的类型和所需的语言环境。

从一开始,考虑到“更规范的答案”的请求日期(大约 2014 年 8 月),将应用自由使用 C++11。

代码的注释版本,其类型对应于 OP:

std::vector<std::uint8_t> convert(std::string const& src)
{
  // error check on the length
  if ((src.length() % 2) != 0) {
    throw std::invalid_argument("conversion error: input is not even length");
  }

  auto ishex = [] (decltype(*src.begin()) c) {
    return std::isxdigit(c, std::locale()); };

  // error check on the data contents
  if (!std::all_of(std::begin(src), std::end(src), ishex)) {
    throw std::invalid_argument("conversion error: input values are not not all xdigits");
  }

  // allocate the result, initialised to 0 and size it to the correct length
  std::vector<std::uint8_t> result(src.length() / 2, 0);

  // run the actual conversion    
  auto str = src.begin(); // track the location in the string
  std::for_each(result.begin(), result.end(), [&str](decltype(*result.begin())& element) {
    element = static_cast<std::uint8_t>(std::stoul(std::string(str, str + 2), nullptr, 16));
    std::advance(str, 2); // next two elements
  });

  return result;
}

代码的模板版本增加了灵活性;

template <typename Int /*= std::uint8_t*/,
  typename Char = char,
  typename Traits = std::char_traits<Char>,
  typename Allocate = std::allocator<Char>,
  typename Locale = std::locale>
std::vector<Int> basic_convert(std::basic_string<Char, Traits, Allocate> const& src, Locale locale = Locale())
{
  using string_type = std::basic_string<Char, Traits, Allocate>;

  auto ishex = [&locale] (decltype(*src.begin()) c) {
      return std::isxdigit(c, locale); };

  if ((src.length() % 2) != 0) {
    throw std::invalid_argument("conversion error: input is not even length");
  }

  if (!std::all_of(std::begin(src), std::end(src), ishex)) {
    throw std::invalid_argument("conversion error: input values are not not all xdigits");
  }

  std::vector<Int> result(src.length() / 2, 0);

  auto str = std::begin(src);
  std::for_each(std::begin(result), std::end(result), [&str](decltype(*std::begin(result))& element) {
    element = static_cast<Int>(std::stoul(string_type(str, str + 2), nullptr, 16));
    std::advance(str, 2);
  });

  return result;
}

convert()函数可以基于basic_convert()以下内容:

std::vector<std::uint8_t> convert(std::string const& src)
{
  return basic_convert<std::uint8_t>(src, std::locale());
}

活样

于 2014-08-22T14:03:46.187 回答
0

您可以将自己的转换从char { '0','1',...'E','F' } 集添加到uint8_t

uint8_t ctoa(char c)
{
    if( c >= '0' && c <= '9' ) return  c - '0'; 
    else if( c >= 'a' && c <= 'f' ) return 0xA + c - 'a';
    else if( c >= 'A' && c <= 'F' ) return 0xA + c - 'A';
    else return 0;
}

然后很容易将字符串转换为数组:

uint32_t endingSize = strlen(starting)/2;
uint8_t* ending = new uint8_t[endingSize];

for( uint32_t i=0; i<endingSize; i++ )
{
    ending[i] = ( ctoa( starting[i*2] ) << 4 ) + ctoa( starting[i*2+1] );
}
于 2014-08-21T09:06:31.687 回答
0

我会尝试这样的事情:

std::string starting_str = starting;
uint8_t[] ending = new uint8_t[starting_str.length()/2];
for (int i = 0 ; i < starting_str.length() ; i+=2) {
    std::string pair = starting_str.substr( i, i+2 );
    ending[i/2] = ::strtol( pair.c_str(), 0, 16 );
}

没测试过,不过我觉得不错。。。

于 2012-07-26T20:52:16.450 回答
0

uint8_t 通常不超过 unsigned char 的 typedef。如果您正在从文件中读取字符,您应该能够将它们读入 unsigned char 数组,就像使用有符号 char 数组一样容易,而 unsigned char 数组一个 uint8_t 数组。

于 2012-07-26T20:50:08.583 回答
0

这个简单的解决方案应该可以解决您的问题

char* starting = "001122AABBCC";
uint8_t ending[12];

// This algo will work for any size of starting
// However, you have to make sure that the ending have enough space.

int i=0;
while (i<strlen(starting))
{
     // convert the character to string
     char str[2] = "\0";
     str[0] = starting[i];

     // convert string to int base 16
     ending[i]= (uint8_t)atoi(str,16);

     i++;
}
于 2016-06-09T02:42:31.943 回答
-1
uint8_t* ending = static_cast<uint8_t*>(starting);
于 2014-08-20T12:37:20.807 回答