Archived

This topic is now archived and is closed to further replies.

Galileo430

Variables To Chars

Recommended Posts

What do you mean by "transmit?"

Are you asking how to convert one of those numeric data types to a string? If so, there are two ways to do it. You can use the C library function sprintf:

  
int i = -12;
unsigned int u = 4;
float f = 3.14159f;
char string[40 + 1]; // a character array (string) which can hold 40 characters (the + 1 is to add space for the terminator)


sprintf(string, "%d", i);
sprintf(string, "%u", u);
sprintf(string, "%f", f);


Check out documentation for the printf family of functions to learn about the different formatting options.

The other way is to use the STL''s stringstream class, and I don''t know enough about it to say much else about it.

Share this post


Link to post
Share on other sites
What do you mean by "plain text?" Both methods yield a string, and a string is "plain text." One happens to be a C-style string, and the other is a C++-style stream. If you''ve got VC++, look up stringstream in MSDN.

Share this post


Link to post
Share on other sites
You can also use memcpy(), this will give you a char buffer without the null terminator.

  
int i;
char szBuffer[4];

// Copy the int into the char buffer (4 byte int)

memcpy(szBuffer,&i,4);



LostLogic
www.lostlogic.com
Author, Multiplayer Game Programming

Share this post


Link to post
Share on other sites
You shouldn''t assume that an int will be 4 bytes, so in the example, that buffer would have to be dynamically-allocated with sizeof(int), and you''d have to give sizeof(int) as the number of bytes to copy.

More importantly, you will essentially get nonsense. Worse, that nonsense might vary by machine since there are no guarantees about the internal representation of the different data types.

Share this post


Link to post
Share on other sites
You want to do a mapping algo. That means each char value will represent (will be mapped to) a value of the float/int variable. Basically, by using such a system, you can only transmit 256 values of the float/int variable. You must choose such a mapping that the error is as small as possible (the average difference between the float/int variable you have to send and the value that is received on the other end).


The first thing to do is find out the minimum and maximum values of your variable.

With linear mapping, (unsigned char)0 represents the minimum value of your var, (unsigned char)255 represents the maximum.

unsigned char toChar (float f, float min, float max) //use on server
{
assert(f > min && f < max);
return (unsigned char)(255.0f * (f - min) / (max - min));
}


float toFloat (unsigned char c, float min, float max)
{
float d = (float)c / 255.0f;
return (d * max + (1 - d) * min);
}


If you have a variable that has a wide range, but you know most of the time it only has small values, you can use exponential mapping. In this form of mapping, your 256 float/int values mapped to char values are not evenly spaced like in the linear mapping. There are more values near the minimum value and the gap between two consecutive values gets wider and wider as you approach the maximum value.


unsigned char toChar (float f, float min, float max) //use on server
{
assert(f > min && f < max);
return (unsigned char)(pow (BASE, f - min) / pow (BASE, max - min) * 255.0);
}

float myLogarithm (float base, float number)
{
return log (number) / log (base);
}

float toFloat (unsigned char c, float min, float max)
{
float d = (float)c / 255.0f * pow (BASE, max - min);
return min + myLogarithm (BASE, d);
}


I don''t have time to test these, if I made a mistake and they don''t work, tell me and I''ll repair them. Anyway, the general idea is that there should be more values and more accuracy for the areas in which your variable is more likely to appear. You can make custom mapping schemes, where you simply precalculate an array of 256 float values and send in the message a char that is the index of the closest match of a float value in this array. To speed up such a scheme, sort that array and use binary search to locate the closest match.


There''s more you can do to make sure that your vars will actually have values in a small range. The easiest solution that comes to mind is to use delta values.

IE. if your float variable is the position of a player, you can send in one packet the whole float value, then in the next five packets send the char version of the difference between the new value and the old value. These differences (deltas) generally are very small, so using a char to store them can loose little accuracy. Of course, this might not always be true, and it is good to be able to send the whole value anyway if the difference from the last update is too big (if the player can teleport, just send his position as a float).

Hope that helped.

Share this post


Link to post
Share on other sites
Oh, now I think I understand what you''re trying to do. You''re trying to convert variables of different types to a series of bytes you can transmit, right?

If that''s right, then you can use the memcpy trick. The only point of concern is endianness. For example, your machine is most likely little-endian, but the protocol you''re using might require the data to be in big-endian format. If the endiannesses are different, you''ll have to swap the order of the bytes in that group of bytes that represents the variable.

Share this post


Link to post
Share on other sites