Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Advanced pointer typecasting

Reply
Thread Tools

Advanced pointer typecasting

 
 
Robert Street
Guest
Posts: n/a
 
      02-20-2004
Hi!

I'm rather new at c++ and I'm totally confused with this kind of
typecasting:

typedef signed char int8_t;
typedef signed short int16_t;

typedef struct broadcast_hdr
{
broadcast_type_t broadcast_type;
uint16_t items_n;
uint16_t size_n;
} broadcast_hdr_t;

typedef struct broadcast_type
{
char ac;
char bc;
uint16_t number_n;
} broadcast_type_t;

typedef struct ob_levels_price
{
uint16_t maskA_n;
uint16_t maskB_n;
uint8_t levels_c;
uint8_t items_c;
char filler_2_s [2];
} ob_levels_price_t;

void HandleBroadcast(int8_t* broadcast, uint16_t length)
{
static broadcast_type_t typeA = {'B','I',9};
static broadcast_type_t typeB = {'B','D',6};
static broadcast_type_t typeC = {'B','O',14};

broadcast_type_t* bc;

bc = (broadcast_type_t*)broadcast;

if (memcmp(bc, &typeC, sizeof(broadcast_type_t)) == 0)
{
SpecificBroadcast(broadcast, length);
return;
}

}

void SpecificBroadcast(int8_t* broadcast, uint16_t length)
{

ob_levels_price_t* obPriceVolumes = (ob_levels_price_t*)broadcast;

broadcast_hdr_t* bc = (broadcast_hdr_t*)broadcast;
uint32_t substart = sizeof(*bc);
uint8_t *pBc = (uint8_t*)bc;
}

Can someone explain to me SpecificBroadcast. I don't understand how
the contents of an signed char (int8_t) can be converted to a struct
(ob_levels_price_t, broadcast_hdr_t) through its address. What could
possibly be the contents of the broadcast variable???

Really stumped.

Thanks in advance.
 
Reply With Quote
 
 
 
 
Jack Klein
Guest
Posts: n/a
 
      02-20-2004
On 19 Feb 2004 19:01:35 -0800, http://www.velocityreviews.com/forums/(E-Mail Removed) (Robert Street)
wrote in comp.lang.c++:

> Hi!
>
> I'm rather new at c++ and I'm totally confused with this kind of
> typecasting:


You should be, it almost certainly indicates bad design. It depends
on one guaranteed feature of the language, and a lot of things that
are not guaranteed.

One guarantee that the language makes is that a pointer to any type of
object can be converted, with a suitable cast, to a pointer to one of
the character types or to a pointer to void. If such a pointer
originally points to a valid object of its type, the char or void
pointer can later be cast back to a pointer of the original object
type and it will still point to the same object.

There is no such guarantee for any other type of pointer, as other
types of headers may use fewer bits of information than pointer to
char or void.

There is most certainly no guarantee that just any arbitrary pointer
to char or void can be cast to a pointer to another object type and be
valid. It might not have the proper alignment for the other object
type, and cause undefined behavior when used to access that type.

> typedef signed char int8_t;
> typedef signed short int16_t;
>
> typedef struct broadcast_hdr
> {
> broadcast_type_t broadcast_type;
> uint16_t items_n;
> uint16_t size_n;
> } broadcast_hdr_t;
>
> typedef struct broadcast_type
> {
> char ac;
> char bc;
> uint16_t number_n;
> } broadcast_type_t;
>
> typedef struct ob_levels_price
> {
> uint16_t maskA_n;
> uint16_t maskB_n;
> uint8_t levels_c;
> uint8_t items_c;
> char filler_2_s [2];
> } ob_levels_price_t;
>
> void HandleBroadcast(int8_t* broadcast, uint16_t length)
> {
> static broadcast_type_t typeA = {'B','I',9};
> static broadcast_type_t typeB = {'B','D',6};
> static broadcast_type_t typeC = {'B','O',14};
>
> broadcast_type_t* bc;
>
> bc = (broadcast_type_t*)broadcast;
>
> if (memcmp(bc, &typeC, sizeof(broadcast_type_t)) == 0)


The line above is very problematic. Even if "broadcast" was obtained
by casting the address a broadcast_type_t to pointer to signed char,
so there are no alignment issues, and even if the original
broadcast_type_t contained {'B', 'O', 14 }, there is no requirement
that the two structures compare equal when passed to memcmp().

Padding is allowed in structures everywhere except before the first
member. There can be padding in between members, and after the last
member. The value of the padding bytes can be different in two
structures whose actual members are identical, causing the memcmp() to
fail.

> {
> SpecificBroadcast(broadcast, length);
> return;
> }
>
> }
>
> void SpecificBroadcast(int8_t* broadcast, uint16_t length)
> {
>
> ob_levels_price_t* obPriceVolumes = (ob_levels_price_t*)broadcast;
>
> broadcast_hdr_t* bc = (broadcast_hdr_t*)broadcast;
> uint32_t substart = sizeof(*bc);
> uint8_t *pBc = (uint8_t*)bc;
> }
>
> Can someone explain to me SpecificBroadcast. I don't understand how
> the contents of an signed char (int8_t) can be converted to a struct
> (ob_levels_price_t, broadcast_hdr_t) through its address. What could
> possibly be the contents of the broadcast variable???
>
> Really stumped.
>
> Thanks in advance.


This code uses C casts, although a C++ static_cast could do the same
job.

As I said above, a pointer to void or one of the character types can
hold a pointer to any type of object. Unless the pointer originated
as a pointer to that type of object, you get undefined behavior if you
try to access an object of that type through it.

There is nothing particularly C++ about this code, it is completely
compatible with C. But it is a bad design in either language. There
are much more sensible, and portable, ways to do whatever this code
does, such as putting the structure types in a union and passing a
pointer to the union.

The code also depends on specifically non-portable behavior, the fact
that on some implementation there will be no padding in the
broadcast_type_t structure so that two structures with
member-by-member equality will compare equal when passed to memcmp().
There is no such guarantee in either C or C++, and there are compilers
where the memcmp() might fail a good part of the time even if all the
individual members of the two structures compare equal.

This code is bad, and should not be emulated.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
 
Reply With Quote
 
 
 
 
Nick Hounsome
Guest
Posts: n/a
 
      02-20-2004

"Robert Street" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...
> Hi!
>
> I'm rather new at c++ and I'm totally confused with this kind of
> typecasting:
>
> typedef signed char int8_t;
> typedef signed short int16_t;


snip

> void SpecificBroadcast(int8_t* broadcast, uint16_t length)
> {
>
> ob_levels_price_t* obPriceVolumes = (ob_levels_price_t*)broadcast;
>
> broadcast_hdr_t* bc = (broadcast_hdr_t*)broadcast;
> uint32_t substart = sizeof(*bc);
> uint8_t *pBc = (uint8_t*)bc;
> }
>
> Can someone explain to me SpecificBroadcast. I don't understand how
> the contents of an signed char (int8_t) can be converted to a struct
> (ob_levels_price_t, broadcast_hdr_t) through its address. What could
> possibly be the contents of the broadcast variable???
>


This is what people always used to do for low level i/o stuff before void*.
Although they usually use a plain old char*

Some people still do this because when you are doing low level stuff you
often need to do byte address calculations
and that requires a pointer to something of size 1. e.g.

// read a message from a socket
void readn(int fd,void* buf,int size)
{
do
{
int nread = read(fd,buf,size); // read should take void*
size -= nread;
buf = (char*)buf + nread; // cast required purely to do
arithmetic
} while(size);
}

Even then it is best to make the function parameter void* because although
making it 'byte'* would make the function simpler
it would often force the caller to cast to something it is not.
eg.
ob_levels_price_t x;
SpecificBroadcast(&x,sizeof(x)); // will not coompile despite the fact
that it clearly should according to SpecificBroadcast
SpecificBroadcast((uint8_t*)&x,sizeof(x)); // will compile - using
reinterpret_cast only makes it uglier

Another good reason to use void* rather than some sort of char* is this is
that ostream<< will do the wrong thing and debuggers will spew garbage when
doing stack dumps or showing local vars.

IMHO It would be a nice idea to allow pointer arithmetic on void* as if it
was a pointer to 'byte' - I don't think it would
do any harm in real programs.



 
Reply With Quote
 
Robert Street
Guest
Posts: n/a
 
      02-21-2004
"Nick Hounsome" <(E-Mail Removed)> wrote in message news:<9wrZb.9287$(E-Mail Removed)>...
> "Robert Street" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed) om...
> > Hi!
> >
> > I'm rather new at c++ and I'm totally confused with this kind of
> > typecasting:
> >
> > typedef signed char int8_t;
> > typedef signed short int16_t;

>
> snip
>
> > void SpecificBroadcast(int8_t* broadcast, uint16_t length)
> > {
> >
> > ob_levels_price_t* obPriceVolumes = (ob_levels_price_t*)broadcast;
> >
> > broadcast_hdr_t* bc = (broadcast_hdr_t*)broadcast;
> > uint32_t substart = sizeof(*bc);
> > uint8_t *pBc = (uint8_t*)bc;
> > }
> >
> > Can someone explain to me SpecificBroadcast. I don't understand how
> > the contents of an signed char (int8_t) can be converted to a struct
> > (ob_levels_price_t, broadcast_hdr_t) through its address. What could
> > possibly be the contents of the broadcast variable???
> >

>
> This is what people always used to do for low level i/o stuff before void*.
> Although they usually use a plain old char*
>
> Some people still do this because when you are doing low level stuff you
> often need to do byte address calculations
> and that requires a pointer to something of size 1. e.g.
>
> // read a message from a socket
> void readn(int fd,void* buf,int size)
> {
> do
> {
> int nread = read(fd,buf,size); // read should take void*
> size -= nread;
> buf = (char*)buf + nread; // cast required purely to do
> arithmetic
> } while(size);
> }
>
> Even then it is best to make the function parameter void* because although
> making it 'byte'* would make the function simpler
> it would often force the caller to cast to something it is not.
> eg.
> ob_levels_price_t x;
> SpecificBroadcast(&x,sizeof(x)); // will not coompile despite the fact
> that it clearly should according to SpecificBroadcast
> SpecificBroadcast((uint8_t*)&x,sizeof(x)); // will compile - using
> reinterpret_cast only makes it uglier
>


Thanks for the help.

One more question, why can the code cast the uint8_t pointer to *both*
ob_levels_price_t* and broadcast_header_t*? Shouldn't the original
address be simply pointing to one type of struct? Any ideas?

> Another good reason to use void* rather than some sort of char* is this is
> that ostream<< will do the wrong thing and debuggers will spew garbage when
> doing stack dumps or showing local vars.
>
> IMHO It would be a nice idea to allow pointer arithmetic on void* as if it
> was a pointer to 'byte' - I don't think it would
> do any harm in real programs.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
what is typecasting a pointer to the type (void *)p mean? Abhishek C Programming 16 01-26-2006 04:47 AM
typecasting pointer issues PapaTodd@gmail.com C++ 9 11-09-2005 12:47 AM
typecasting towards a pointer to a K&R style declared function dis C Programming 2 06-11-2004 10:36 PM
Typecasting char pointer to structure venkatesh C++ 1 12-06-2003 06:46 AM
Question regarding pointer typecasting and manipulation Arun Prasath C Programming 2 11-26-2003 10:28 PM



Advertisments