Double char to single short? Easy C++ question.

Started by
7 comments, last by l0calh05t 11 years, 7 months ago
Hello!
Recently I posted a thread for my memory leaks. I managed to fix them, but I didn't want to bring the topic again so I didn't answer.
So I said: Why shoud I believe in what other software says about my program? Lets track all the allocation and dellocations. This way I'll be sure everything is alright. But if I start... hmh it would be better if I create a whole memory pool. It would be more experience for me...

-Intro & reasons why I need the answer of the questions. Skip if you want, I just can't ask the question without giving more information than it is needed tongue.png-

Ok I read some memory pool tutorials... I didn't understand anything so I created a fresh C++ project and started coding it. Amazing but it is behaving really well even if I overload the global new operator 0_0. I made all tests I could imagine.. The alloc time is really good is most cases, however I could make a situation which requires large amout of time. This time I started editing it to get it working better.

All chunks from my pool need a header which saves their status. I already made an algorithm which will do the job but it requires 2 bytes header for each chunk(now I'm using one byte, and each bit has different meaning for my chunk). My new functions working with bits are using unsigned shorts as arguments/parameters. So..

How do I take two bytes(chars) and convert them to a single short? (everything is unsigned)

char a[2]; a[0] = 1; a[1] = 2;
short b = a;(!?!? how shoud I cast it)
cout << b; It shoud print 258




EDIT: Didn't notice I have posted it in game programming. Sorry!

Advertisement
[font=courier new,courier,monospace]short b = short(a[0])<<8 | short(a[1]);[/font]
or
[font=courier new,courier,monospace]short b = *reinterpret_cast<short*>(a);[/font]
Ohhh... Seriously.. I'm playing with bitwise oprations only in the last 48 hours. And I absolutely forgot that I can do this...
I tried the second option but I messed with the C style casting I used. And it returned me a number around 65000..
Thanks.
The bit-wise method is arguably "safer"...but perhaps this is faster?

[source lang="cpp"]char ch[2] = { 'A', 'B' };

char *cPtr = &ch;

short sh = *((short *)cPtr);[/source]

All we're doing here is obtaining the address (pointer) of "ch". Then, in one line, we cast it to a short* and dereference it. Just a quick and easy way of doing things when you're working with simple data-types of a known, fixed size.

EDIT:

Before anyone jumps my case on this I just wanted to show the OP what goes on "under the hood". As Hodgman suggest, *reinterpret_cast<short*>(a) is probably a much cleaner way to go about things and reduces the potential of programming error. But if the OP has no idea how it works then using it won't be very helpful. And what I showed is valid in C, C++, C# and quite a few other languages other than C++.
_______________________________________________________________________________
CEO & Lead Developer at ATCWARE™
"Project X-1"; a 100% managed, platform-agnostic game & simulation engine

Please visit our new forums and help us test them and break the ice!
___________________________________________________________________________________
what I showed is valid in C, C++...
Unfortunately, you're code is invalid tongue.png char ch[2] = { 'A', 'B' };
char *cPtr = ch;//correct - a T[] can decay into a T* (this is what's going on in the reinterpret_cast example)
char *cPtr = &ch;//error - cannot convert from address-of-T[] to T*
char *cPtr = &ch[0];//correct - the address of the first item will be a pointer to the start of the array
short sh = *((short *)cPtr);//this is equivalent to the reinterpret_cast above, known as a C-style cast.
// I actually prefer these C-style casts as 'reinterpret_cast' is (IMHO) ugly :)
short sh = *((short *)ch);//also correct - just folding line 1 into the cast

Unfortunately, you're code is invalid Posted Image


Say waaahhhh!? biggrin.png

Here, run this:

///////////////////////////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
char ch[2] = { 'A', 'B' };
char *cPtr = ch;
short sh = *((short *)cPtr);

char dst[2];
short *pSh = (short *)dst;
*pSh = sh;

cout << dst[0] << dst[1] << endl;

return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////

Output: AB

So I don't see how my code was invalid? tongue.png </scratch head>


EDIT: Oh, were you talking about how I accidentally used an ampersand in front of the array indentifier, which would actually create a char**? Twas just a typo, but your reply was nonetheless correct; as is my above example, where I didn't make the same typo! smile.png

EDIT (AGAIN): BTW, did you fix that in my first post for me? ;-)
_______________________________________________________________________________
CEO & Lead Developer at ATCWARE™
"Project X-1"; a 100% managed, platform-agnostic game & simulation engine

Please visit our new forums and help us test them and break the ice!
___________________________________________________________________________________
Your first post had a typo:
1) [font=courier new,courier,monospace]char *cPtr = &ch;[/font]
vs
2) [font=courier new,courier,monospace]char *cPtr = ch;[/font]
Don't do the array-cast-thing if you want your bytes to be laid out in a predefined order. It is not portable. It works on Intel-style (x86, x86-64) and other little endian machines, but will may fail on some other architectures, like big endian ARM or PowerPC. If you get your data into your bytes using it as a short, you're fine though.

The shift-operator on the other hand "knows" about endianness and will produce the correct result. You should however use unsigned char instead of char, or else very funny things may happen (shift handles negative number in a special way, preserving the sign bit, thus messing up all your nice computations). Consider this for example:


char y[2] = {0x00, 0x80};
std::cout << std::hex << short(y[0]) << ", " << short(y[1]) << ", " << (short(y[0]) << 8 | short(y[1]))<< std::endl;


You'd expect it to print "0, 80, 80", but in reality it's more likely to print "0, ff80, ffffff80" which is not at all what you want. Do the same with unsigned data types and it will work...

You should however use unsigned char instead of char, or else very funny things may happen (shift handles negative number in a special way, preserving the sign bit, thus messing up all your nice computations).


Well... char is a bit strange anyways because char, signed char and unsigned char are three distinct types. A char may be signed or unsigned if not specified.

This topic is closed to new replies.

Advertisement