Длинный вопрос для очень простого & Новобранец проблемы, НО все же мне нужно несколько советов.
Итак, у меня есть двоичный файл, который мне нужно проанализировать. Этот файл начинается с некоторой магической строки, которая содержит нулевой символ (\0
). давайте определим как ab\0cd
,
Я пишу метод, который возвращает true, если какой-то файл начинается с магической строки.
#define MAGIC_STRING "ab\0cd"
bool IsMagicFile(const wpath& pathFile)
{
string strData;
if (!ReadFile(pathFile, strData))
return false;
if (strData.size() < 5)
return false;
string strPrefix = strData.substr(0, 5);
if (strcmp(strPrefix.c_str(), MAGIC_STRING) != 0)
return false;
return true;
}
Что беспокоит меня в приведенном выше коде, так это то, что я «жестко» предполагаю, что размер магической строки 5
,
что если завтра волшебная нить изменится? сказать:
#define MAGIC_STRING "abe\0fcd"
макрос строки изменен, и код больше не работает должным образом.
#define MAGIC_STRING "ab\0cd"
bool IsMagicFile(const wpath& pathFile)
{
string strMagic = MAGIC_STRING;
string strData;
if (!ReadFile(pathFile, strData))
return false;
if (strData.size() < strMagic.size())
return false;
string strPrefix = strData.substr(0, strMagic.size());
if (strcmp(strPrefix.c_str(), MAGIC_STRING) != 0)
return false;
return true;
}
Якобы избавился от жестко заданной проблемы с размером, НО размер strMagic
на самом деле не 5, а 2. строка заканчивается \0
#define MAGIC_STRING "ab\0cd" // CAUTION - MAGIC_STRING & MAGIC_STRING_SIZE must be changes together
#define MAGIC_STRING_SIZE 5 // CAUTION - MAGIC_STRING & MAGIC_STRING_SIZE must be changes together
bool IsMagicFile(const wpath& pathFile)
{
string strData;
if (!ReadFile(pathFile, strData))
return false;
if (strData.size() < MAGIC_STRING_SIZE)
return false;
string strPrefix = strData.substr(0, MAGIC_STRING_SIZE);
if (strcmp(strPrefix.c_str(), MAGIC_STRING) != 0)
return false;
return true;
}
Это решило первую проблему, но я до сих пор не получил желаемого бесшовного изменения магической строки.
Является ли попытка 3 достаточно хорошей? у вас есть лучший подход?
Вместо использования определения макроса вы можете определить постоянный массив символов. Например
const char MAGIC_STRING[] = "abe\0fcd";
В этом случае количество символов, исключая завершающий ноль, равно
sizeof( MAGIC_STRING ) - 1
Для сравнения необработанных байтов вы можете использовать стандартную функцию C memcmp
предоставляя количество сравниваемых байтов, которое равно выражению выше.
Вот демонстрационная программа
#include <iostream>
#include <string>
#include <cstring>
#include <iterator>
const char MAGIC_STRING[] = "abe\0fcd";
int main()
{
std::string s( std::begin( MAGIC_STRING ), std::prev( std::end( MAGIC_STRING ) ) );
if ( memcmp( s.c_str(), MAGIC_STRING, sizeof( MAGIC_STRING ) - 1 ) == 0 )
{
std::cout << "The string starts with the MAGIC_STRING" << std::endl;
}
return 0;
}
Его вывод
The string starts with the MAGIC_STRING
Если вы точно знаете, что ваша волшебная строка будет содержать \0
тогда вы могли бы написать свой собственный size(string str)
функция, которая будет возвращать правильную длину, продолжая считать после первого \0
,
Если неизвестно, сколько \0
s есть в волшебной строке, я бы посоветовал вам пойти с попыткой 3.
Если вам нужен код, который поможет вам в правильном направлении для size
метод, дай мне знать.
Лично я бы не использовал MACROS. Также я бы не использовал функции, предназначенные для строк с нулевым символом в конце, таких как станд :: зЬгстр. Вы можете проверить, содержит ли начало строки определенную последовательность символов, используя станд :: равны от стандарта <algorithm>
библиотека:
// create a character array to preserve compile time size
// but remember string literals add a null-terminator extra character
const char magic_string[] = "ab\0cd";
bool IsMagicFile(const wpath& pathFile)
{
string strData;
if (!ReadFile(pathFile, strData))
return false;
// -1 to avoid null terminator from magic_string character array
return std::equal(magic_string, magic_string + sizeof(magic_string) - 1,
strData.begin());
}