Использование статической строки с вектором

Моя история программирования связана с C и CPython. Пожалуйста, потерпите меня здесь.

Чтобы помочь мне выучить C++, я конвертирую одну из своих старых программ C для использования C++ OOP, но она не работает так, как я хочу. Меня не волнует скорость. Я просто забочусь об обучении.

Вот мой старый код C, который я хочу поместить в класс Checksum:

    //This is the standard CRC32 implementation
    //"rollingChecksum" is used so the caller can maintain the current 
    //checksum between function calls
    unsigned int CalculateChecksum(unsigned char* eachBlock, int* sbox, long lengthOfBlock, unsigned int rollingChecksum)
    {
       int IndexLookup;
       int blockPos;

       for(blockPos = 0; blockPos < lengthOfBlock; blockPos++)
       {
         IndexLookup = (rollingChecksum >> 0x18) ^ eachBlock[blockPos];
         rollingChecksum = (rollingChecksum << 0x08) ^ sbox[IndexLookup];
       }
       return rollingChecksum;
    }

Итак, вот как я перевел это в код C++'ey:

 void Checksum::UpdateStream(std::vector<unsigned char> binaryData)
 {
   unsigned int indexLookup;
   unsigned int blockPos;

   for(blockPos = 0; blockPos < binaryData.size(); blockPos++)
   {
      indexLookup = (this->checksum >> 0x18) ^ binaryData[blockPos];
      this->checksum = (this->checksum << 0x08) ^ this->sbox[indexLookup];
   }
 }

Но затем, когда я пытаюсь его использовать:

int main(int argc, char* argv[])
{
 Checksum Test;
 Test.UpdateStream("foo bar foobar");
 std::cout << Test.getChecksum() << std::endl;
}

Я получаю эту ошибку:

1>main.cpp(7) : error C2664: 'Checksum::UpdateStream' : cannot convert parameter 1 from 'const char [15]' to 'std::vector<_Ty>'
1>        with
1>        [
1>            _Ty=unsigned char
1>        ]
1>        No constructor could take the source type, or constructor overload resolution was ambiguous

Я решил использовать векторный контейнер выше вместо строкового класса из-за как этот вопрос оказался на StackOverflow и потому что я хочу использовать здесь бинарные данные.

ЖЕЛАЕМЫЙ РЕЗУЛЬТАТ: Как я могу передать этому методу как строки, так и двоичные данные для вычисления его контрольной суммы? Нужно ли мне перегружать его или набирать строку в основном? Я полностью потерян.


person user407896    schedule 29.01.2011    source источник


Ответы (4)


Вы можете скопировать содержимое массива char в вектор, используя std::copy:

std::vector< char > vector;
char str[] = "foo bar foobar";
vector.resize( sizeof(str)-1 ); // thanks to Alf (see comments)
std::copy( str, str+sizeof(str)-1, vector.begin() );

или еще лучше с помощью конструктора std::vector:

char str[] = "foo bar foobar";
std::vector< char > vector( str, str+sizeof(str)-1 );

Обратите внимание, что этот код скопирует всю строку, но завершающую \0 (опять же, дополнительные сведения см. в комментариях).

person peoro    schedule 29.01.2011
comment
... и, возможно, перезаписать Checksum::UpdateStream, чтобы он брал массив символов, преобразовывал его в std::vector и вызывал Checksum::UpdateStream(std::vector‹unsigned char› binaryData) с этим. - person thbusch; 29.01.2011
comment
Я как раз собирался предложить это. +1. - person Fred Foo; 29.01.2011
comment
Пока я пишу это, ваш первый код — Undefined Behavour. Пожалуйста исправьте. - person Cheers and hth. - Alf; 29.01.2011
comment
-1 Ваш второй пример кода тоже неверен (sizeof вместо strlen). - person Cheers and hth. - Alf; 29.01.2011
comment
@ Альф П. Штайнбах: а? Что не так с sizeof и с первым фрагментом? - person peoro; 29.01.2011
comment
@ Альф П. Штайнбах: о, ты прав насчет std::copy. Я просто хотел показать тип этой переменной vector, но да, этот код не работает, исправил, спасибо! Насчет sizeof я не уверен; Это зависит от того, что OP нужно делать с вектором; Я думаю, вы правы, что для контрольной суммы последняя '\0' не нужна, но тогда и strlen тоже не подходит: она не даст ожидаемой контрольной суммы для строки типа "\0\1\2\3"; заменит его на sizeof(str)-1. - person peoro; 29.01.2011
comment
@peoro: лучше сделайте это resize вместо reserve (все еще неправильно) и sizeof вместо szieof (опечатка). :-) - person Cheers and hth. - Alf; 29.01.2011
comment
Alf P. Steinbach: аууу, чувствую себя новичком! :-( - person peoro; 29.01.2011

Ваш класс контрольной суммы имеет дело с необработанными данными байтов, которые могут поступать откуда угодно, поэтому базовый интерфейс не должен навязывать преобразование, например, в. std::vector.

т.е. тип формального аргумента unsigned char const* исходного кода C был и остается в порядке.

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

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

char const  s[] = "blah blah";
std::vector<unsigned char> const v( s, s + strlen( s ) );

Ура и чт.,

person Cheers and hth. - Alf    schedule 29.01.2011

Вы не можете создать вектор из строкового литерала. Ну, по крайней мере, не напрямую. Это должно работать:

std::string tmp = "foo bar foobar"
Test.UpdateStream(std::vector<unsigned char>(tmp.begin(), tmp.end()));

Вы также можете обновить свою подпись UpdateStream, чтобы использовать (const std::vector<unsigned char>& binaryData), чтобы избежать копирования, поскольку вам не нужно ее изменять.

Чтобы сократить код, вы можете предоставить перегрузку UpdateStream для строки:

void Checksum::UpdateStream(const std::string& str) {
    UpdateStream(std::vector<unsigned char>(str.begin(), str.end()));
}
person Cat Plus Plus    schedule 29.01.2011
comment
Я попытался использовать ваше решение для перегрузки метода. Однако это приводит к тому, что контрольные суммы меняются каждый раз, когда я запускаю программу. Если я изменю параметр метода на std::string str, число будет стабильным каждый раз. - person user407896; 29.01.2011

В С++ строковый литерал в этом контексте будет распадаться на указатель char на первый char, и нет неявного конструктора, создающего вектор из указателя char. Кроме того, unsigned char и char являются разными типами, и хотя между ними существуют неявные правила преобразования, правил преобразования между указателем на unsigned char и указателем на char нет.

Я предлагаю не пытаться изучать C++ путем экспериментов, потому что C++ — сложный язык с долгой историей эволюции... он был разработан многими разными умами и даже формальными комитетами. Во многих местах C++ далек от интуитивного или логичного, потому что некоторые правила являются результатом эволюции, эффекта комитета или обратной совместимости с вещами, которых сейчас больше не существует.

Добавьте к этому проблему, заключающуюся в том, что когда вы делаете ошибку в C++, вы легко получаете демонов UB вместо ангелов ошибок времени выполнения, и вы поймете, что экспериментирование — это просто неверный путь к C++. Неважно, насколько умным может быть человек, невозможно вывести историю с помощью логических рассуждений. Историю надо изучать.

Сделайте себе одолжение, возьмите "Язык программирования C++" и прочтите его от корки до корки: есть много вещей, которые человеку с хорошим опытом работы с C будет легко понять, если вы поместите их в структуру и контекст. Другие книги, которые мне очень понравились и которые, по моему мнению, также легко читаются, — это «Часто задаваемые вопросы по C++» Маршалла Клайна и серия «Effective» Скотта Мейерса.

C++ — хороший язык, но он легко может стать вашим худшим кошмаром, если вы подойдете к нему не с той стороны.

person 6502    schedule 29.01.2011