Как преобразовать символ фиксированной длины * в число или преобразовать символ с ненулевым завершением * в число?

#c

#c

Вопрос:

 #include <iostream>   // std::cout
#include <string>     // std::string, std::stoi

int main ()
{
  const char* arrNumber = "ff000A;";
  const std::string firstNum = std::string(arrNumber, 2);
  const std::string secondNum = std::string(arrNumber 2, 4);

  const int i_first = std::stoi(firstNum, nullptr, 16);
  const int i_second= std::stoi(secondNum, nullptr, 16);

  std::cout << "i_first: " << i_first << std::endl;
  std::cout << "i_second: " << i_second << std::endl;
  return 0;
}
  

У меня здесь два вопроса.

  1. Как преобразовать символ фиксированной длины char* в число? В приведенном выше примере нам нужно извлечь первые два шестнадцатеричных символа в целое число. Предлагаемый метод медленный из-за построения a std::string , и я ищу лучшее решение, подобное следующему прототипу.

      stoi_x(const char* start_, size_t len, int base = 10)
      

    Учитывая этот прототип, приведенный выше пример можно записать следующим образом:

      const int i_first = stoi_x(arrNumber, 2, 16);
      
  2. Как преобразовать символ char* без нулевого терминатора в число?. Опять же, я ищу лучшее решение, подобное следующему прототипу.

      stoi_x(const char* start_, char end_, int base = 10)
      

    Учитывая этот прототип, приведенный выше пример можно записать следующим образом:

      const int i_second = stoi_x(arrNumber 2, ';', 16);
      

Комментарии:

1. @SergeyA это было из любопытства, извините, если это вызвало сомнение в мотивах операций

2. из любопытства: почему у вас есть строки с ненулевым завершением?

3. @user463035818, некоторые сетевые протоколы НЕ используют » в качестве завершителя для строки. Вместо этого он указывает только длину и начало строки.

Ответ №1:

Вы можете использовать std::from_chars , и это поможет вам проделать большую часть пути прямо из коробки. Он принимает указатели на начальный элемент и один за последним элементом и преобразует его в число. Если он вообще не может преобразовать строку, он заполнит код ошибки в возвращаемом объекте, в противном случае он преобразует то, что может, и возвращает указатель на часть данных, которые он не смог преобразовать в возвращаемом объекте. Его использование в вашем коде изменяет его на

 int main ()
{
    const char* arrNumber = "ff000A;";

    int i_first, i_second;
    std::from_chars(arrNumber, arrNumber   2, i_first, 16);
    std::from_chars(arrNumber   2, arrNumber   6, i_second, 16); 

    std::cout << "i_first: " << i_first << std::endl;
    std::cout << "i_second: " << i_second << std::endl;
    return 0;
}
  

Если вам не нравится, что вы не можете присвоить результат преобразования постоянной переменной, вы можете обернуть его в свою собственную функцию, например

 template<typename T>
auto from_chars(char const * begin, char const * end, int base = 10)
{
    T ret{};
    std::from_chars(begin, end, ret, base);
    return ret;
}
  

и затем вы можете использовать его как

 int main ()
{
    const char* arrNumber = "ff000A;";

    const int i_first = from_chars<int>(arrNumber, arrNumber   2, 16);
    const int i_second = from_chars<int>(arrNumber   2, arrNumber   6, 16);

    std::cout << "i_first: " << i_first << std::endl;
    std::cout << "i_second: " << i_second << std::endl;
    return 0;
}
  

Обратите внимание, что я не выполняю никакой обработки ошибок. В производственном коде вы должны проверять, произошла ли ошибка, поскольку std::from_chars не будет генерироваться никаких исключений.

Комментарии:

1. вы можете подумать о добавлении базового параметра в свой post, поскольку std::from_chars поддерживает это, а OP требует шестнадцатеричного преобразования. Спасибо

2. @q0987 просто сделал так, как я видел, я пропустил это.

3. Сегодня я узнал от вас о новой функции и благодарю вас!

4. @q0987 Добро пожаловать. Рад помочь. Существует to_chars также часть счетчика from_chars , которая также должна быть максимально быстрой.