Casting values in C/C++

Started by
9 comments, last by crudbreeder 18 years, 9 months ago
I am trying to figure out how to store numbers (bytes, ints, longs...) in a string or an array of chars, and read them back out again. For instance, if I can convert a long value into an array of 4 bytes, I suppose I could store the 4 bytes somewhere in an array of chars (string[]) such that string to string[i+4] could be read to reproduce the original long value. How would I do this programmatically in C/C++? ...Stip
Advertisement
Maybe I could use memcpy in the string.h library?

Ex:

#include <string.h>
#include <stdlib.h>

int main ()
{
long* longVal;
char longBuff[4];

memcpy (longBuff, longVal, 4);
return 0;
}

Would this work? (Sorry, my C is rusty and my development environment is down.)

...Stip


do you have any restrictions on the size of the strings cause you could store them as the number (e.g. 1234567 stored as "1234567") and just do an atol(string). if this isn't an option you could just store it as a byte[] and cast them to the values you want.
Ugly and dirty version:

int firstint = 6;
*(int*)&string = firstint;
int secondint = *(int*)&string;

Or using memcpy :

int firstint = 6;
memcpy ( &string, &firstint, sizeof(int) );
int secondint;
memcpy ( &secondint, &string, sizeof(int) );

You would probably need to have some kind of index table to keep track of the position of each value within the string.

The big question is; Why on earth would you want to do this?? It's very very very ugly thing to do.

If you REALLY need to store values binary in a char array it would be better to store them in a struct and the cast the struct as a char array into whatever function uses it.

In any case, if the char array is ever treated as a "string" anywhere in your program you will run into problems with zeros causing your string to be cut short.
I'd like to suggest you add what you're trying to do in general (i.e. not copy ints into a string array, but the actual problem). I agree with crudbreeder that it's ugly. Maybe if we know more we could suggest a better solution.

BTW, you might want to consider creating your own class and defining the [] operator.
An arrow through the eye is still an arrow through the eye.
If you mean parsing strings to and from other types (including user defined types) then the standard C++ way would be to use string streams or something that uses string streams internally (like boost::lexical_cast) i.e.:

#include <sstream> // string streams#include <string>  // basic_string#include <iostream>int main() {   std::ostringstream oss; // output string stream   oss << "an int: " << 30434 << " float: " << 0.0343f;   std::string s = oss.str();   std::cout << s << std::endl;}
Quote:Original post by crudbreeder
int firstint = 6;
*(int*)&string = firstint;
int secondint = *(int*)&string;

Keep in mind that this may crash on some processors due to misaligned data.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
I think crudbreeder has the solution. I am trying to send data via winsock between a client and server. The send and recv functions take char arrays as arguments, and I need to figure out how to send chars, ints, longs, and possibly other strings back and forth. Someone gave an example of casting a struct in the networking forum. It looks like the solution I was looking for. Can anyone give me a link giving me some more information about this, or possibly some examples? Thanks.

...Stip
Don't take offence to this, but if you don't understand basic C/C++ concepts like typecasting, you probably shouldn't be learning winsock, because it's useless until you can use it asyncronously, and for that you need either a window HWND (preferably a message only HWND), or the ability to randomly check sockets with select();

http://ensim.bkshosting.com/~admin83/w2wrap.rar

That's my winsock 2 wrapper. It's crappy, but it works and it shows you everything.

As you said, the functions do indeed take char pointers, but these pointers to data, not a string, and it doesn't have to be NULL terminated, so you can typecast anything to the char * and as long as you tell the send and recv function how big it is, no problems. For example:

struct myStruct {    int myvar;    char mystring[33];};(in code)myStruct thing = { 666, "Why hello, world" };send(mysocket, (char *)&thing, sizeof(myStruct), 0);


If you have any more problems with Winsock, email me at kawahee@gmail.com
Quote:Original post by snk_kid
If you mean parsing strings to and from other types (including user defined types) then the standard C++ way would be to use string streams or something that uses string streams internally (like boost::lexical_cast)



Just to expand on boost::lexical_cast:

#include <boost/lexical_cast.hpp>#include <cassert>#include <string>using std::string;using boost::lexical_cast;int main () {    double pi_d = 3.14159265359;    string pi_s = lexical_cast< string >( pi_d );    assert( pi_s == "3.14159265359" ); //this may actually fail due to rounding errors or the like, but I'm just going to be lazy and ignore that for this example :-P    string onetwothree_s = "123";    int onetwothree_i = lexical_cast< int >( onetwothree_s );    assert( onetwothree_i == 123 );}


Since lexical_cast uses streams internally, you can use hex specifiers, etc. and have them interpreted as desired.

EDIT: Err sorry, you mean binary data, not an actual textual conversion.

Well, I happen to have a couple of classes for pretty much just this in my library... basically, they use the shift iterator to convert an integer into either a big endian or little endian representation of the integer divided up into 4 bytes (unsigned chars), and/or said bytes back into a full integer. Here's the relevant code:

//Typedefs:typedef unsigned long value_type; //full integer valuetypedef unsigned char indexed_value_type; //sub-integer valuetypedef size_t size_type;//Common variables:static const size_type size = size_v;//notes: size_v == template parameter, "4" for a full 4 byte integerindexed_value_type data[ size ];//Big endian byte array -> Integer valueoperator value_type () const {	value_type value = 0;	for ( size_type i = 0 ; i < size ; ++i ) value += data << ((size - i - 1) * CHAR_BIT);	return value;}//Integer value -> Big endian byte arraybig_endian_integer( value_type value ) {	for ( size_type i = 0 ; i < size ; ++i ) data = (value >> ((size - i - 1) * CHAR_BIT)) & UCHAR_MAX;}//Little endian byte array -> Integer valueoperator value_type () const {	value_type value = 0;	for ( size_type i = 0 ; i < size ; ++i ) value += data << (i * CHAR_BIT);	return value;}//Integer value -> Little endian byte arraylittle_endian_integer( value_type value ) {	for ( size_type i = 0 ; i < size ; ++i ) data = (value >> (i * CHAR_BIT)) & UCHAR_MAX;}


I've made this code both endian-free (in the sense of processor endian) and does not do funky pointer casting which could result in crashes on 64 bit platforms.

This topic is closed to new replies.

Advertisement