473,725 Members | 2,212 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

casting X* to char*

A colleague asked me something along the lines of the following today.

For some type X he has:

X* px = new X[sz];

Then he wants to convert px to a char* (I'm guessing for the purpose of
serializing the object array).

I can think of three ways to do this:

char* pc = (char*) px;
char* pc = static_cast<cha r*> (static_cast<vo id*> (px));
char* pc = reinterpret_cas t<char*> (px);

From my reading of the standard it seems that the results of these
casts are all unspecified.

Is this true?

In practice, would these casts ever do anything besides the obvious?

Is there any portable way to access the bytes of an object's representation?

Thanks,
Mark
May 30 '06 #1
33 3655
Mark P wrote:
A colleague asked me something along the lines of the following today.

For some type X he has:

X* px = new X[sz];

Then he wants to convert px to a char* (I'm guessing for the purpose of
serializing the object array).
What for? Why not provide your own operator<< and operator>> for type X?
Lets consider what happens if type X is composed of primitive types,
containers, pointers and references.

Doesn't it make sense that its a better solution to stream those
componants rather than carying out a byte-by-byte transfer of the
object? What if the target of the transfer uses a different architecture
(or a different compiler). Why would you want to have to deal with the
type's padding?

The proposed solution above and below therefore constitute a good
example of undefined behaviour. Not to mention unneccesary bits being
transferred and having to detect the source and target architectures as
well as writing a new function to handle each possibility.
Why do it the hard way with undefined results when writing a simple
operator rids you of all the headaches?

std::ostream& operator<<(std: :ostream& os, const X& x)
{
// stream the relevent componants into os
// return os;
}

and make the above function a friend of type X.
It doesn't get any simpler. And its portable.

I can think of three ways to do this:

char* pc = (char*) px;
char* pc = static_cast<cha r*> (static_cast<vo id*> (px));
char* pc = reinterpret_cas t<char*> (px);

From my reading of the standard it seems that the results of these
casts are all unspecified.
I don't see a cast, i see a non-portable hack. The above is in fact
guarenteed to fail. Don't casting unless you develop a healthy respect
for what they do.

Is this true?

In practice, would these casts ever do anything besides the obvious?

Is there any portable way to access the bytes of an object's
representation?


Of course there is. The key is to access the *relevent* bytes. What is
relevent can very well depend on the requirements and needs.
You are assuming than an object will occupy in memory the sum of the
allocations of its componants. If your computer did not rely on
segment+index addressing schemes it would slow to a crawl. In C++ its
critical to provide code that is transparent to the platform its running
on. Your code needs to stream the object's components with no regards to
the architecture/platform underneath. Thats what C++ is all about.

Lets slap together a dumb example.

#include <iostream>
#include <ostream>

class X
{
char c;
int n;
public:
X() : c(' '), n(0) { }
~X() { }
};

int main()
{
X x;
std::cout << "sizeof(x) = " << sizeof(x) << std::endl;
}

/*
sizeof(x) = 8
*/

Interestingly enough on my system a char is 1 byte and an integer is 4
bytes (your mileage may well vary). So why the size of 8 bytes? Answer:
padding. Why would you ever want to pay an 8 byte transfer when you can
simply stream the char and integer? No hacking required. With a portable
result too.

Lets prove it, how about streaming type X objects to your standard
output? After all, it uses a std::ostream too, doesn't it? You can
replace std::cout with any interface that can accept a standard output
stream. All you need is a simple operator<< to stream your precious type
in any fashion you desire.

#include <iostream>
#include <ostream>

class X
{
char c;
int n;
public:
X() : c(' '), n(0) { } // default ctor
X(char c_, int n_) : c(c_), n(n_) { }
~X() { }
/* friend operator<< */
friend std::ostream& operator<<(std: :ostream& os, const X& r_x)
{
os << "c = " << r_x.c; // stream the char
os << "; n = " << r_x.n; // stream the integer
return os << std::endl;
}
};

int main()
{
X xa('a', 0);
X xb('b', 1);

std::cout << "xa: " << xa;
std::cout << "xb: " << xb;

}

/*
xa: c = a; n = 0
xb: c = b; n = 1
*/

Are you now seeing the simplicity and power in the design? What if the
private member integer was in fact another class? No problem, write an
op<< for it too. What if i needed a container of 1000 X elements? What
if you needed to stream the whole container of 1000 X elements to
standard output?

Your way you would need hundreds of lines of code. And it would still
not be portable. I can create, load and stream a container of 1000 X
elements in 3 lines of code excluding includes. Yes: 3. Completely
portable and reusable.

hint: std::vector< X > vn(1000); // and std::copy(...) to std::cout

May 31 '06 #2

Mark P wrote:
A colleague asked me something along the lines of the following today.

For some type X he has:

X* px = new X[sz];

Then he wants to convert px to a char* (I'm guessing for the purpose of
serializing the object array). .... Is there any portable way to access the bytes of an object's representation?


Yes. The correct way is indeed to cast it to a char*. There is one
catch.
The object must have a POD type. POD is Plain Old Data, which roughly
means any old C object that can be memcpy'd as bytes. Almost all C++
features will make a type non-POD, see the standard or any advanced
book.

Of course, it may be a portable way to *access* the bytes of a POD, but
that
still doesn't mean those *bytes* are portable. And the bytes of a
pointer are
notoriously unusable later on.

HTH,
Michiel Salters

May 31 '06 #3
Salt_Peter wrote:
Mark P wrote:
A colleague asked me something along the lines of the following today.

For some type X he has:

X* px = new X[sz];

Then he wants to convert px to a char* (I'm guessing for the purpose of
serializing the object array).


What for? Why not provide your own operator<< and operator>> for type X?
Lets consider what happens if type X is composed of primitive types,
containers, pointers and references.

[snip]

Good advice. See also these FAQs:

http://www.parashift.com/c++-faq-lit...alization.html

Cheers! --M

May 31 '06 #4
Mark P posted:

char* pc = (char*) px;

Pefectly okay.

char* pc = static_cast<cha r*> (static_cast<vo id*> (px));

Perfectly okay.

char* pc = reinterpret_cas t<char*> (px);

Pefectly okay.

From my reading of the standard it seems that the results of these
casts are all unspecified.

Incorrect. EVERY object is made up of bytes, regardless of its type, and
regardless of whether it qualifies as a POD. The following code is
perfectly okay:

#include <string>
#include <iostream>

template<class T>
void PrintObjectByte s( const T &obj )
{
const unsigned char * const p_last_byte =
reinterpret_cas t<const unsigned char *>(&obj) + ( sizeof(obj) - 1
);

for( const unsigned char *p = reinterpret_cas t<const unsigned char *>
(&obj);
/* Nothing Condition */;
++p )
{
std::cout << static_cast<uns igned>(*p) << '\n';

if ( p == p_last_byte ) break;
}
}
#include <cstdlib>

int main()
{
std::string str("Hello World!");

PrintObjectByte s( str );

std::system("PA USE");
}
-Tomás
May 31 '06 #5
posted:

Yes. The correct way is indeed to cast it to a char*. There is one
catch.
The object must have a POD type. POD is Plain Old Data, which roughly
means any old C object that can be memcpy'd as bytes. Almost all C++
features will make a type non-POD, see the standard or any advanced
book.

You're incorrect.

Find me the fanciest, most advanced class you can find... and I guarantee
you it's made up of bytes.

A type doesn't have to be a POD in order for you to access its bytes. See
my post elsewhere in thread for an example.
-Tomás
May 31 '06 #6
Tomás wrote:
EVERY object is made up of bytes, regardless of its type, and
regardless of whether it qualifies as a POD.
Sure, but the meaning of those bytes might be different than expected.
For instance, a virtual table might be included or the compiler might
have inserted padding between members. If one is serializing an object
(as the OP indicated), then those bytes are not necessarily meaningful
when unserialized at some later time or on some other machine.
The following code is
perfectly okay:

#include <string>
#include <iostream>

template<class T>
void PrintObjectByte s( const T &obj )
{
const unsigned char * const p_last_byte =
reinterpret_cas t<const unsigned char *>(&obj) + ( sizeof(obj) - 1
);

for( const unsigned char *p = reinterpret_cas t<const unsigned char *>
(&obj);
/* Nothing Condition */;
++p )
{
std::cout << static_cast<uns igned>(*p) << '\n';

if ( p == p_last_byte ) break;
Use the for-loop condition instead of this line, which unnecessarily
duplicates the functionality of the for-loop construct.
}
}


Cheers! --M

May 31 '06 #7
mlimber posted:

if ( p == p_last_byte ) break;


Use the for-loop condition instead of this line, which unnecessarily
duplicates the functionality of the for-loop construct.

I want the condition to be tested AFTER the loop body, sort of like how you
can have a "do loop" instead of a "while loop".

Alas, C++ doesn't provide a "do for" loop.
-Tomás
May 31 '06 #8
Tomás wrote:
mlimber posted:

if ( p == p_last_byte ) break;

Use the for-loop condition instead of this line, which unnecessarily
duplicates the functionality of the for-loop construct.

I want the condition to be tested AFTER the loop body, sort of like how you
can have a "do loop" instead of a "while loop".

Alas, C++ doesn't provide a "do for" loop.


do {
// loop body
} while (condition);
May 31 '06 #9
red floyd posted:
Tomás wrote:
mlimber posted:

if ( p == p_last_byte ) break;
Use the for-loop condition instead of this line, which unnecessarily
duplicates the functionality of the for-loop construct.

I want the condition to be tested AFTER the loop body, sort of like
how you can have a "do loop" instead of a "while loop".

Alas, C++ doesn't provide a "do for" loop.


do {
// loop body
} while (condition);

Please re-read my previous post before you post another example of "do
loop".
-Tomás

May 31 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

231
23169
by: Brian Blais | last post by:
Hello, I saw on a couple of recent posts people saying that casting the return value of malloc is bad, like: d=(double *) malloc(50*sizeof(double)); why is this bad? I had always thought (perhaps mistakenly) that the purpose of a void pointer was to cast into a legitimate date type. Is this wrong? Why, and what is considered to be correct form?
19
1749
by: Ramesh Tharma | last post by:
Hi, Is any one knows what's wrong with the following code, I was told that it will compile and run but it will crash for some values. Assume that variables are initilized. char* c; long* lg;
14
2629
by: mr_semantics | last post by:
I have been reading about the practise of casting values to unsigned char while using the <ctype.h> functions. For example, c = toupper ((unsigned char) c); Now I understand that the standard says this about the <ctype.h> functions: "The header <ctype.h> declares several functions useful for classifying and mapping characters.166) In all cases the argument is an int, the
2
1849
by: Alex Vinokur | last post by:
classes that have virtual methods hold pointer to virtual table as additional implicit data member. So, sizeof of such classes is sizeof of all data (as struct-POD) plus 4. It seems that use of casting for such classes is quite dangerous. See sample below. Why does reinterpret_cast permit such a casting? ===================== Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for
5
5926
by: brekehan | last post by:
I've always been a little sketchy on the differences between static, dynamic, and reinterpret casting. I am looking to clean up the following block by using C++ casting instead of the C style casting. from what I am reading, I should use reinterpret cast in this situation, is that correct? Why does static and dynamic casting fail me? // please excuse the windows types, it is necessary in this code, // but the question remains C++ related
24
2101
by: Francine.Neary | last post by:
I've read that you should always cast the argument you pass to isupper(), isalnum(), etc. to unsigned char, even though their signature is int is...(int). This confuses me, for the following reason. The is...() functions can either accept a character, or EOF. But now suppose (as is common) that EOF==(int) -1. Then (unsigned char) EOF will be 255, which is a valid character value! So this casting destroys the possibility to pass EOF to...
17
2224
by: sophia.agnes | last post by:
Hi , I was going through peter van der linden's book Expert C programming, in this book there is a section named "How and why to cast" the author then says as follows (float) 3 - it's a type conversion and the actual bits change. if you say (float) 3.0 it is a type disambiguation,and the compiler can plant the correct bits in the first place.some people say that
32
2378
by: alex.j.k2 | last post by:
Hello all, I have "PRECISION" defined in the preprocessor code and it could be int, float or double, but I do not know in the code what it is. Now if I want to assign zero to a "PRECISION" variable, which of the following lines are correct:
101
4322
by: Tinkertim | last post by:
Hi, I have often wondered if casting the return value of malloc() (or friends) actually helps anything, recent threads here suggest that it does not .. so I hope to find out. For instance : char *tmp = NULL;
10
3784
by: Alex Vinokur | last post by:
Hi, Is it possible to do C++-casting from const pair<const unsigned char*, size_t>* to const pair<unsigned char*, size_t>* ? Alex Vinokur
0
8888
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8752
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9401
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9257
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
9113
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
6702
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4519
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4784
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
2635
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.