Поиск строк в потоке байтов

#c #c 11

Вопрос:

У меня есть ниже программа, в которой я пытаюсь найти подстроку в константном беззнаковом символе * байт

 #include <iostream>
#include <string.h>

using namespace std;

int main()
{

const unsigned char bytes[] = { 
        0x49, 0x4e, 0x56, 0x49, 0x54, 0x45, 0x20, 0x73, 0x69, 0x70, 0x3a, 0x61, 0x62, 0x63, 0x40, 0x76
        , 0x6f, 0x64, 0x61, 0x66, 0x6f, 0x6e, 0x65, 0x2e, 0x75, 0x6b, 0x20, 0x53, 0x49, 0x50, 0x2f, 0x32
        , 0x2e, 0x30, 0x0d, 0x0a, 0x56, 0x69, 0x61, 0x3a, 0x20, 0x53, 0x49, 0x50, 0x2f, 0x32, 0x2e, 0x30
        , 0x2f, 0x55, 0x44, 0x50, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x30, 0x2e, 0x31, 0x38, 0x2e, 0x31, 0x36
        , 0x38, 0x3a, 0x35, 0x30, 0x36, 0x31, 0x3b, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x3d, 0x7a, 0x39
        , 0x68, 0x47, 0x34, 0x62, 0x4b, 0x2d, 0x31, 0x31, 0x32, 0x31, 0x38, 0x2d, 0x31, 0x2d, 0x30, 0x0d
        , 0x0a, 0x46, 0x72, 0x6f, 0x6d, 0x3a, 0x20, 0x73, 0x69, 0x70, 0x70, 0x20, 0x3c, 0x73, 0x69, 0x70
        , 0x3a, 0x62, 0x62, 0x40, 0x6a, 0x69, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x3b, 0x74, 0x61, 0x67
        , 0x3d, 0x31, 0x31, 0x32, 0x31, 0x38, 0x53, 0x49, 0x50, 0x70, 0x54, 0x61, 0x67, 0x30, 0x30, 0x31
        , 0x0d, 0x0a, 0x54, 0x6f, 0x3a, 0x20, 0x73, 0x75, 0x74, 0x20, 0x3c, 0x73, 0x69, 0x70, 0x3a, 0x61
        , 0x62, 0x63, 0x40, 0x76, 0x6f, 0x64, 0x61, 0x66, 0x6f, 0x6e, 0x65, 0x2e, 0x75, 0x6b, 0x3e, 0x0d
        , 0x0a, 0x43, 0x61, 0x6c, 0x6c, 0x2d, 0x49, 0x44, 0x3a, 0x20, 0x31, 0x2d, 0x31, 0x31, 0x32, 0x31
        , 0x38, 0x40, 0x31, 0x30, 0x2e, 0x31, 0x30, 0x2e, 0x31, 0x38, 0x2e, 0x31, 0x36, 0x38, 0x0d, 0x0a
        , 0x43, 0x53, 0x65, 0x71, 0x3a, 0x20, 0x31, 0x20, 0x49, 0x4e, 0x56, 0x49, 0x54, 0x45, 0x0d, 0x0a
        , 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x3a, 0x20, 0x73, 0x69, 0x70, 0x3a, 0x73, 0x69, 0x70
        , 0x70, 0x40, 0x31, 0x30, 0x2e, 0x31, 0x30, 0x2e, 0x31, 0x38, 0x2e, 0x31, 0x36, 0x38, 0x3a, 0x35
        , 0x30, 0x36, 0x31, 0x0d, 0x0a, 0x4d, 0x61, 0x78, 0x2d, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64
        , 0x73, 0x3a, 0x20, 0x37, 0x30, 0x0d, 0x0a, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20
        , 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74
        , 0x0d, 0x0a, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x3a, 0x20, 0x3c, 0x73, 0x69, 0x70, 0x3a, 0x31, 0x30
        , 0x2e, 0x31, 0x30, 0x2e, 0x31, 0x38, 0x2e, 0x31, 0x35, 0x34, 0x3a, 0x35, 0x30, 0x37, 0x30, 0x3b
        , 0x6c, 0x72, 0x3e, 0x2c, 0x3c, 0x73, 0x69, 0x70, 0x3a, 0x61, 0x69, 0x72, 0x74, 0x65, 0x6c, 0x2e
        , 0x63, 0x6f, 0x6d, 0x3b, 0x6c, 0x72, 0x3e, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74
        , 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69
        , 0x6f, 0x6e, 0x2f, 0x53, 0x44, 0x50, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d
        , 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x0d, 0x0a, 0x0d
        , 0x0a
    };

  const unsigned char* byte = bytes; // this is the buffer received from the other layers
 
  //I am trying to convert it to string using reinterpret_cast
  const std::string charStr = reinterpret_cast<const char*>(byte);


  if(!(charStr.find("REGIST")!= std::string::npos)) //the above bytes of character is having this string it should be found in the buffer
  {
     std::cout<<"Not found";
     return;
  }
std::cout<<"found";
return 0;
}
 

Но это может привести к сбросу ядра в высокопроизводительных системах, а функция поиска также является дорогостоящей.

Каков наилучший способ выделить строку в буфере const без знака char*? Допустим, функция advanced c не поддерживается.

И как лучше всего решить эту проблему со старыми версиями c (03) и с продвинутой версией c (11)?

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

1. Почему это должно привести к сбросу ядра в высокопроизводительных системах?

2. В вашем коде есть большая проблема в том, что вы пытаетесь создать std::string массив байтов с ненулевым окончанием. Это вызывает неопределенное поведение

3. Ваш код также действителен в c 03. Построение str std::string (что, кстати, неверно из-за отсутствия нулевого терминатора) — это та часть, которая занимает большую часть времени. Если вы можете использовать c 17, вы можете использовать std::string_view . И вы уверены find , что это дорого?

4. И каков наилучший способ решения этой проблемы -Вопросы, задающие «лучший способ», почти никогда не поддаются ответу, потому что то, что является «лучшим», в высшей степени субъективно.

5. Немного за C 03/C 11 пределами запрошенной области, но у C 20 вас есть std::boy_moore_searcher

Ответ №1:

Операция может привести к дампу ядра, поскольку она имеет неопределенное поведение — std::string ожидает указатель на массив символов, заканчивающийся нулем, в то время как массив, который вы передаете ему, не заканчивается нулем. Из — за этого конструктор std::string считывает данные из памяти за пределами буфера до тех пор, пока не найдет нулевой терминатор-эта операция может легко выполнить сегментацию.

Одна вещь, которую вам нужно иметь, — это длина буфера. Затем вы можете передать его в конструктор строки:

 const std::string charStr{ reinterpret_cast<const char*>(byte), bufferLength };
 

Теперь, если по какой-то причине эта операция окажется критичной для производительности, вы, скорее всего, не захотите выделять буфер и копировать в него всю строку.
Чтобы избежать этого, вы можете использовать string_view либо std::string_view c 17 , либо absl::string_view библиотеку abseil c 11. Вы передаете те же параметры конструктору и string_view сохраняете представление в диапазоне символов, не копируя его (обратите внимание на время жизни буфера!). Вы можете позвонить find по string_view тому же номеру, что и на std::string .

Однако, если вы можете редактировать содержимое и размер буфера, самым простым способом, по-видимому, является добавление нулевого терминатора » » в конце буфера и вызов std::strstr из <cstring>

Ответ №2:

Первый способ (простой): если вы можете изменить свой массив и добавить символ x00 в конце, вы можете использовать C-функцию strstr .

Во-вторых: вы можете написать собственную версию функции поиска. Это довольно просто.

Ответ №3:

Если вы добавляете » » или 0x00 в конце массива, ваш код должен работать должным образом.

Вы выполняете поиск подстроки, это «дорого». Вы могли бы реализовать его самостоятельно, но это будет совсем то же самое, что найти.

пройдитесь по массиву байтов и найдите только первую букву, если она найдена, сравните остальную часть строки поиска. Но звучит более или менее как «находка».