Why does this code snippet not work when i take it out of function scope

Started by
2 comments, last by Jason Z 9 years, 10 months ago

I saw in beej network guide some code that packs a int into a char and I didnt understand some things about it so I was just playing around with it and for one reason or another I moved the snippet directly into main. I found out it doesn't work right when I do that. Notice it outputs a really big number if I do the operations of the pack functions in main. Any particular reason why?



#include <iostream>
#include <bitset>
#include <limits>
using namespace std;

void packi32(unsigned char *buf, unsigned long i)
{
	*buf++ = i>>24; 
	*buf++ = i>>16;
	*buf++ = i>>8; 
	*buf++ = i;

	//cout << buf[0] << " " << buf[1] << " " << buf[2] << " " << buf[3] << endl;
}

unsigned long unpacki32(unsigned char *buf)
{
	return (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
}

int main()
{
	unsigned char * buf = new unsigned char[4];
	unsigned long i = 254;
	unsigned long result = 0;

	*buf++ = i >> 24;
	*buf++ = i >> 16;
	*buf++ = i >> 8;
	*buf++ = i;

	result = unpacki32(buf);
	cout << result << endl;

	memset(buf, 0, sizeof(buf));

	packi32(buf, i);
	result = unpacki32(buf);

	cout << result;

	cin.get();
}

[size="5"]http://innercirclegames.freeforums.org
Email me at: innercirclegames@hotmail.com
Advertisement

You're incrementing buf as you write to it, then passing buf into unpacki32. buf no longer points to your original buffer, it points to the very end of the buffer. So when you call unpacki32 for the first time, you're just unpacking a bunch of random memory that happens to be after your 4 char buffer. Then you memset that memory (which you don't even own, btw) and call packi32 which only increments it's local copy of the buf param that you passed it, so the buf in main is untouched and when you call unpacki32 for the second time you're unpacking the memory that was written to by packi32 and not some uninitialized memory.

If you did something like this it would probably work:


int main()
{
        size_t buf_size = 4;
	unsigned char * buf = new unsigned char[buf_size];
        unsigned char * orig = buf;
	unsigned long i = 254;
	unsigned long result = 0;

	*buf++ = i >> 24;
	*buf++ = i >> 16;
	*buf++ = i >> 8;
	*buf++ = i;

	result = unpacki32(orig);
	cout << result << endl;

        // can't do sizeof(buf) here. buf is just a char* and sizeof(char*) != the size of
        // the buffer generally (though it is in this case, since your buffer is only 
        // four bytes long, but that's just a happy coincidence)
	memset(orig, 0, buf_size); 

        buf = orig; // reset your buffer pointer

	packi32(buf, i);
	result = unpacki32(buf); // can use buf or orig here, since packi32 doesn't modify buf in this scope

	cout << result;

	cin.get();
}
1. If you need an array of a small number of chars, I would default to putting them on the stack, i.e. "unsigned char buf[4]", instead of using new. Your sizeof would work if you did that.

2. If you want to test your function's ability to pack and unpack an int into a char array, you might want to choose an int that actually takes more than one byte to store.


1. If you need an array of a small number of chars, I would default to putting them on the stack, i.e. "unsigned char buf[4]", instead of using new. Your sizeof would work if you did that.

You could also use std::array for a fixed size array. That makes it much harder to forget to release the dynamic memory, and sizing should work properly there too. But I agree, for small stuff like this, stack allocation would probably be fine.

This topic is closed to new replies.

Advertisement