casting struct from char*... 
Author Message
 casting struct from char*...

If I have a variable abc of struct type (say struct abctype {int a1; char
a2[10];};), and I used memcpy to copy the content of abc to a varable tmp of
type char*.  Is it possible to cast tmp back to type struct abctype later?
If yes, how?
--



Fri, 24 Jan 2003 03:00:00 GMT  
 casting struct from char*...

comp.lang.c.moderated:

Quote:
> If I have a variable abc of struct type (say struct abctype {int a1; char
> a2[10];};), and I used memcpy to copy the content of abc to a varable tmp of
> type char*.  Is it possible to cast tmp back to type struct abctype later?
> If yes, how?

First of all, you can't copy anything to the area pointed to by a
pointer to char unless it points to sufficient memory, perhaps
obtained from malloc().  Second, if you are going to use arrays of
char to hold arbitrary non-text data, you should make them arrays of
unsigned char.  Signed char can have trap representations, and plain
char is signed on many implementations.

Now let me get this straight, you have code something like this:

#include <stdio.h>
#include <string.h>

typedef struct { int a1; char a2[10]; } abctype;

int main(void)
{
   abctype abc = { 3, "hello" };
   unsigned char car [sizeof abc];
   abctype *abcptr = (abctype *)car;
   memcpy(car, &abc, sizeof abc);
   printf("car.a1 = %d\n", abcptr->a1);
   return 0;

Quote:
}

If this sums up what you want to do, the answer is "it depends".  What
it depends on is how you obtained the memory that the pointer to
(unsigned) char points to.

If you defined a pointer to char and allocated memory to it with
malloc(), calloc(), or realloc(), this is guaranteed to work on all
platforms.

If you defined the memory as an array of chars, as in my sample above,
then no, it is not guaranteed to work and the behavior is undefined.

Some architectures have alignment requirements.  When you define a
variable of a particular type (like abctype abc in my example), the
compiler ensures that it is located in memory with the proper
alignment.

When you allocate memory with the <stdlib.h> memory allocation
functions, you are guaranteed that the pointer returned is aligned
properly for any data type.

But there is no alignment requirement for chars, or arrays of char.
So if you defined the array of chars like my sample, the pointer might
not be properly aligned to address your structure.  The copy with
memcpy will work with no problems, but trying to access elements of
the structure through the pointer to char, even after casting, may
violate alignment requirements and, at least on some operating
systems, cause an error that terminates the program.

If you must do this for some reason, allocate the memory dynamically.

Jack Klein
--
Home: http://jackklein.home.att.net
--



Sat, 25 Jan 2003 03:00:00 GMT  
 casting struct from char*...

Quote:
>If I have a variable abc of struct type (say struct abctype {int a1; char
>a2[10];};), and I used memcpy to copy the content of abc to a varable tmp of
>type char*.  Is it possible to cast tmp back to type struct abctype later?
>If yes, how?

In short, no.  

If you tried to copy the struct into the pointer itself, it would not
fit.

If you copy the struct into the area the pointer points to, then you
must cast tmp to pointer to struct but you still have a potential
alignment problem.  A char * has the least restrictive alignment and
may point to an area of memory such that the members of the struct do
not have the proper alignment.

<<Remove the del for email>>
--



Sat, 25 Jan 2003 03:00:00 GMT  
 casting struct from char*...

Quote:

> If I have a variable abc of struct type (say struct abctype {int a1; char
> a2[10];};), and I used memcpy to copy the content of abc to a varable tmp of
> type char*.  Is it possible to cast tmp back to type struct abctype later?
> If yes, how?

Assuming that you copy the content to *the location pointed to by* tmp,
*and* that you initialized tmp, *and* you initialized to a properly
aligned address, yes. But in general, no.

The following should work:

unsigned char* tmp_ptr; /* unsigned char has no trap representations */
tmp_ptr = malloc( sizeof(abc) ); /* malloc gives aligned memory */
memcpy(tmp_ptr, &abc, sizeof(abc) );
struct abctype abc_ptr = (struct abctype*) tmp_ptr;

HTH,
Michiel Salters
--



Sat, 25 Jan 2003 03:00:00 GMT  
 casting struct from char*...

Quote:

> If I have a variable abc of struct type (say struct abctype {int a1; char
> a2[10];};), and I used memcpy to copy the content of abc to a varable tmp of
> type char*.  Is it possible to cast tmp back to type struct abctype later?
> If yes, how?

That depends.  If the char* points to the beginning of a block of
memory allocated using malloc (or one if its friends) then it
should be sufficiently aligned to make the cast safe.
(struct abctype*)tmp

If it's not, however, then you won't be able to rely on the char*
being sufficiently aligned to point to an instance of your struct.
It will compile, and may work sometimes, but it may not work in all
cases or on all platforms/compilers.

/peter
--



Sat, 25 Jan 2003 03:00:00 GMT  
 casting struct from char*...

Quote:

> If I have a variable abc of struct type (say struct abctype {int a1; char
> a2[10];};), and I used memcpy to copy the content of abc to a varable tmp of
> type char*.  Is it possible to cast tmp back to type struct abctype later?
> If yes, how?

Copying a struct onto a pointer was a mistake, even if you were
lucky enough that it all fit.  If it *did* fit, use memcpy to
copy it back to a similar struct.  (Casting won't work, because
there is no natural conversion between these two types of data.)
However, you really need to reexamine what you were doing,
because it makes little sense.  Pointers don't point to anything
useful after you dump some non-pointer object onto them.
--



Sat, 25 Jan 2003 03:00:00 GMT  
 casting struct from char*...


Quote:
> If I have a variable abc of struct type (say struct abctype {int a1;
> char a2[10];};), and I used memcpy to copy the content of abc to a
> varable tmp of type char*.  Is it possible to cast tmp back to type
> struct abctype later?
> If yes, how?

I would suggest (without trying anything or looking up the std)
creating the appropriate types with typedef, using sizeof to base
everything on the abctype, and creating a union.  The array is of
type char[sizeof(abctype)], not char *.  This should automagically
handle packing and sizeof(int) differences between systems.

However, simply because of the automagic handling, THIS WILL NOT
function to pass the structure between different systems.  To do
that you would have to convert each field to a byte stream
independently.

--

 http://www.qwikpages.com/backstreets/cbfalconer/
--



Sat, 25 Jan 2003 03:00:00 GMT  
 casting struct from char*...

Quote:

> If I have a variable abc of struct type (say struct abctype {int a1; char
> a2[10];};), and I used memcpy to copy the content of abc to a varable tmp of
> type char*.

I hope you actually copied to the area to which tmp pointed.

Quote:
> Is it possible to cast tmp back to type struct abctype later?

You can't cast anything to a structure type, but you can cast tmp to
struct abctype *.

#include <stdlib.h>
#include <stdio.h>

struct abctype
{
    int a1;
    char a2[10];

Quote:
};

int
main (void)
{
    /* have a variable abc of struct type */
    struct abctype abc = { 501, "Brainwash" };

    /* variable tmp of type char* */
    char *tmp;

    /* make it point to something */
    tmp = malloc (sizeof (struct abctype));
    if (tmp == NULL)
        return EXIT_FAILURE;

    /* copy the content of abc to the memory pointed by the variable
       (not to the variable itself, since it wouldn't fit) */
    memcpy (tmp, &abc, sizeof (struct abctype));

    /* cast tmp to struct abctype * (not struct abctype but a pointer) */
    {
        struct abctype *def = (struct abctype *) tmp;

        /* now def points to the same memory area as tmp */
        def->a1 = 666;
    }

    /* show that abc hasn't changed */
    printf ("abc = { %d, \"%s\" }\n", abc.a1, abc.a2);

    /* copy the changed data from *tmp */
    memcpy (&abc, tmp, sizeof (struct abctype));

    /* now it has changed */
    printf ("abc = { %d, \"%s\" }\n", abc.a1, abc.a2);

    /* that's all folks */
    return 0;

Quote:
}

--



Sat, 25 Jan 2003 03:00:00 GMT  
 casting struct from char*...
Are you clear on what a "cast" does?
And what memcpy() does?

A cast doesn't change anything - it just tells the compiler that you
realise that what you're doing is not a correct use of types, but you
want to do it anyway. A memcpy() copies what's in memory, byte by byte.
Using a variable which has been declared as a pointer to one type, to
point to something which is another type is bad practice - but in
practice you can get away with it by using casts. Using void* is a much
better idea than using char*.

So, I'm not sure exactly what you question is, but I think this program
will answer it. I compiled it using gcc & it gave the "correct" results.

#include <stdio.h>

main()
{
  typedef struct abctype
  {
    int a1;
    char a2[10];
  } abctype;

  abctype abc,
          *abc_ptr;
  char *my_ptr;

  abc.a1 = 23;
  strcpy ( abc.a2, "my string" );

  my_ptr = (char*)&abc;
  abc_ptr = (abctype*)my_ptr;

  printf ( "The integer is %d\n", abc_ptr->a1 );
  printf ( "The string is [%s]\n", abc_ptr->a2 );

Quote:
}

Paul
--



Sat, 25 Jan 2003 03:00:00 GMT  
 casting struct from char*...

Quote:

> Second, if you are going to use arrays of
> char to hold arbitrary non-text data, you should make them arrays of
> unsigned char.  Signed char can have trap representations, and plain
> char is signed on many implementations.

But the array was read and written only with memcpy, which treats it
as unsigned chars.  Do trap representations matter if the signed chars
are never read/written as such?

IOW, can the following code trigger a trap?

signed char c;
unsigned int i;
for (i = 0; i <= UCHAR_MAX; ++i) {
    *(unsigned char *) &c = i;
    i = *(unsigned char *) &c;

Quote:
}

--



Sat, 25 Jan 2003 03:00:00 GMT  
 casting struct from char*...


Quote:

> >If I have a variable abc of struct type (say struct abctype {int a1;
char
> >a2[10];};), and I used memcpy to copy the content of abc to a varable
tmp of
> >type char*.  Is it possible to cast tmp back to type struct abctype
later?
> >If yes, how?
> In short, no.  

> If you tried to copy the struct into the pointer itself, it would not
> fit.

> If you copy the struct into the area the pointer points to, then you
> must cast tmp to pointer to struct but you still have a potential
> alignment problem.  A char * has the least restrictive alignment and
> may point to an area of memory such that the members of the struct do
> not have the proper alignment.

How about if the pointer came from malloc() and so will (might) be
suitably aligned:

  struct abctype {
    int a1;
    char a2[10];
  } *ptr, abc={1,"hello"};

  char *tmp = malloc(sizeof(struct abctype));

  memcpy(tmp, &abc, sizeof(struct abctype));

  ptr = (struct abctype *)tmp;

I can imagine that this will work pretty much anywhere, but is it standard?

For example is a compiler allowed to notice that the pointer is being
assigned to a char *, and call (or inline) a version of malloc that
returns unaligned memory?
--



Sun, 26 Jan 2003 03:00:00 GMT  
 casting struct from char*...

wrote in comp.lang.c.moderated:

Quote:

> > Second, if you are going to use arrays of
> > char to hold arbitrary non-text data, you should make them arrays of
> > unsigned char.  Signed char can have trap representations, and plain
> > char is signed on many implementations.

> But the array was read and written only with memcpy, which treats it
> as unsigned chars.  Do trap representations matter if the signed chars
> are never read/written as such?

> IOW, can the following code trigger a trap?

> signed char c;
> unsigned int i;
> for (i = 0; i <= UCHAR_MAX; ++i) {
>     *(unsigned char *) &c = i;
>     i = *(unsigned char *) &c;
> }

No, memcpy will not trap on any data, even totally uninitialized data.
The reason for the caution is that if the data is being copied into a
character array, it might just be accessed as individual chars.  If it
is never accessed as individual signed chars, there is no problem.

Of course accessing it as a structure by casting the pointer to char,
the point of the original question, is certainly not defined.

Jack Klein
--
Home: http://jackklein.home.att.net
--



Sun, 26 Jan 2003 03:00:00 GMT  
 casting struct from char*...

wrote in comp.lang.c.moderated:

Quote:



> > >If I have a variable abc of struct type (say struct abctype {int a1;
> char
> > >a2[10];};), and I used memcpy to copy the content of abc to a varable
> tmp of
> > >type char*.  Is it possible to cast tmp back to type struct abctype
> later?
> > >If yes, how?
> > In short, no.  

> > If you tried to copy the struct into the pointer itself, it would not
> > fit.

> > If you copy the struct into the area the pointer points to, then you
> > must cast tmp to pointer to struct but you still have a potential
> > alignment problem.  A char * has the least restrictive alignment and
> > may point to an area of memory such that the members of the struct do
> > not have the proper alignment.

> How about if the pointer came from malloc() and so will (might) be
> suitably aligned:

>   struct abctype {
>     int a1;
>     char a2[10];
>   } *ptr, abc={1,"hello"};

>   char *tmp = malloc(sizeof(struct abctype));

>   memcpy(tmp, &abc, sizeof(struct abctype));

>   ptr = (struct abctype *)tmp;

> I can imagine that this will work pretty much anywhere, but is it standard?

> For example is a compiler allowed to notice that the pointer is being
> assigned to a char *, and call (or inline) a version of malloc that
> returns unaligned memory?

No, the pointer returned by malloc() is guaranteed to be aligned for
any object.  The type of value you are assigning it to makes no
difference.

Consider:

void *v = malloc(sizeof(struct abctype));

The implementation is not allowed to return a pointer that is only
correctly aligned for objects occupying no space at all! :)

Jack Klein
--
Home: http://jackklein.home.att.net
--



Sun, 26 Jan 2003 03:00:00 GMT  
 casting struct from char*...

Quote:

> For example is a compiler allowed to notice that the pointer is being
> assigned to a char *, and call (or inline) a version of malloc that
> returns unaligned memory?

No!  To do that it would have to examine all usage of the
pointer and pointed-to object for the entire lifetime of
the object.  No practical implementation will do that.
--



Mon, 27 Jan 2003 03:00:00 GMT  
 casting struct from char*...


Quote:

> > For example is a compiler allowed to notice that the pointer is being
> > assigned to a char *, and call (or inline) a version of malloc that
> > returns unaligned memory?

> No!  To do that it would have to examine all usage of the
> pointer and pointed-to object for the entire lifetime of
> the object.  No practical implementation will do that.

What I was thinking was that once the you have done
"char *ptr = malloc(size);", it would be undefined to access
that memory as anything else (e.g. "*(double *)ptr = 3.14;"),
but having checked C99 the only reason this is normally
undefined is from 6.3.2.3 7:

  A pointer to an object or incomplete type may be converted
  to a pointer to a different object or incomplete type. If
  the resulting pointer is not correctly aligned (57) for the
  pointed-to type, the behavior is undefined. Otherwise, when
  converted back again, the result shall compare equal to the
  original pointer.

I had assumed the standard said something like this:

  If a pointer to an object is converted to a pointer to
  an object of an incompatible type the behavior is undefined.

But now I know better.

Phil T
--



Tue, 28 Jan 2003 03:00:00 GMT  
 
 [ 18 post ]  Go to page: [1] [2]

 Relevant Pages 

1. casting static char buffer from C/C++ struct to C#

2. NEED HELP in Type casting structs to a char*'s to do comparisons

3. cast from struct to unsigned char*

4. Casting char array to struct

5. Casting a struct to ( char * )

6. How can I cast *struct -> *char

7. Casting *struct -> *char

8. Casting char * to struct *

9. casting of struct element void pointer casting

10. cast pointer to struct to pointer to type of first member of struct

11. QUESTION: Type casting between struct A superset of struct B

12. char^ to const char* casting

 

 
Powered by phpBB® Forum Software