0

My history with programming is in C and CPython. Please bear with me here.

To help me learn C++ I am converting one of my old C programs to use C++ OOP, but it's not working the way I want it to work. I don't care about speed. I just care about learning.

Here's my old C code I want to put into a Checksum class:

    //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;
    }

So here's how I translated it into more C++'ey code:

 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];
   }
 }

But then when I try to use it:

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

I get this error:

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

I decided to use the vector container above instead of the string class because of how this question turned out on StackOverflow and because I want to use binary data here.

DESIRED RESULT: How can I pass both strings and binary data to this method to calculate its checksum? Do I need to overload it or typecast the string in main? I'm completely lost.

Community
  • 1
  • 1
user407896
  • 950
  • 1
  • 8
  • 12

4 Answers4

3

You could copy a char array content into a vector using 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() );

or even better using std::vector constructor:

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

Note that this code will copy the whole string but the terminating \0 (again, see comments for more details).

peoro
  • 25,562
  • 20
  • 98
  • 150
  • 1
    ...and maybe overwrite Checksum::UpdateStream that it takes a char array, converts it to a std::vector and calls Checksum::UpdateStream(std::vector binaryData) with that. – thbusch Jan 29 '11 at 17:04
  • I was just about the suggest this. +1. – Fred Foo Jan 29 '11 at 17:04
  • Your first code is, as I write this, Undefined Behavor. Please fix. – Cheers and hth. - Alf Jan 29 '11 at 17:15
  • -1 Your second code example is also wrong (sizeof instead of strlen). – Cheers and hth. - Alf Jan 29 '11 at 17:16
  • @Alf P. Steinbach: uh? What's wrong with `sizeof` and with the first snippet? – peoro Jan 29 '11 at 17:18
  • @Alf P. Steinbach: oh, you're right about `std::copy`. I just wanted to show the type of that `vector` variable, but yes, that code it's broken, fixing it, thanks! About the `sizeof` I'm not so sure; It depends what OP needs to do with the vector; I guess you're right that for a checksum the last `'\0'` is not wanted, but then `strlen` isn't appropriate too: it won't give the expected checksum for a string like `"\0\1\2\3"`; will replace it with `sizeof(str)-1`. – peoro Jan 29 '11 at 17:39
  • @peoro: better make that `resize` instead of `reserve` (still wrong), and `sizeof` instead of `szieof` (typo). :-) – Cheers and hth. - Alf Jan 29 '11 at 17:43
  • Alf P. Steinbach: awww, I feel like a newbie! `:-(` – peoro Jan 29 '11 at 17:46
1

Your checksum class deals with raw bytes data that can come from anywhere, so that basic interface shouldn't impose conversion to e.g. std::vector.

I.e. the unsigned char const* formal argument type of original C code was and is fine.

However, you can provide higher level wrappers for common callers' types, such as string literal, std::vector, you name it.

If you absolutely want to have a std::vector as the formal argument type for the fundamental function, then you can copy a string literal to it as follows:

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

Cheers & hth.,

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
0

You can't create vector out of string literal. Well, not directly at least. This should work:

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

You could also update your UpdateStream signature to use (const std::vector<unsigned char>& binaryData) to avoid copying, since you don't need to modify it.

To shorten the code, you can provide an overload of UpdateStream for string:

void Checksum::UpdateStream(const std::string& str) {
    UpdateStream(std::vector<unsigned char>(str.begin(), str.end()));
}
Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
  • I attempted to use your solution of overloading the method. However, doing so causes the checksums to change every time I run the program. If I change the method parameter to be "std::string str" the number comes out stable every time. – user407896 Jan 29 '11 at 20:14
0

In C++ a string literal in that context will decay to a char pointer to the first char and there is no implicit constructor making a vector out of a char pointer. Also unsigned char and char are distinct types and while there are implicit conversion rules between them there are no conversion rules between a pointer to unsigned char and a pointer to char.

My suggestion is not to try to learn C++ by experimenting, because C++ is a complex language with a long evolution history... it has been designed by many different minds and even formal committees. In many places C++ is far from intuitive or logical because some rules are the result of evolution, committee effect or backward compatibility with things that now don't exist any more.

Add to that the problem that when you make a mistake in C++ you get easily UB daemons instead of runtime error angels and you'll understand that experimentation is just the wrong path to C++. No matter how smart someone can be there's no way to infer history using logical reasoning. History must be studied.

Do yourself a favor and grab "The C++ Programming Language" and read it cover-to-cover: there are a lot of things that for someone with a strong C background will be easy to understand once you put them in a framework and context. Other books I liked a lot and that are IMO also an easy reading are "C++ FAQs" by Marshall Cline and the "Effective" series from Scott Meyers.

C++ is a nice language but can easily become your worst nightmare if you approach it from the wrong side.

6502
  • 112,025
  • 15
  • 165
  • 265