Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Allocating single memory block for multiple structures (http://www.velocityreviews.com/forums/t318458-allocating-single-memory-block-for-multiple-structures.html)

Everton da Silva Marques 06-03-2004 02:49 PM

Allocating single memory block for multiple structures
 
Hi,

I need to allocate, using malloc(), a single
memory block to hold two structures and a
variable length string. Is it safe (portable,
alignment-wise) to sum up the sizeof's of those
structures and add the length of the string,
as in this snippet?

const char *canonname = "domain.tld";
struct addrinfo *ai;
struct sockaddr_in *sa;

ai = (struct addrinfo *) malloc(sizeof(struct addrinfo) +
sizeof(struct sockaddr_in) +
strlen(canonname) + 1);

sa = (struct sockaddr_in *) (((char *) ai) + sizeof(struct addrinfo));
sa->sin_family = PF_INET;
sa->sin_port = htons(80);
sa->sin_addr.s_addr = INADDR_ANY;

ai->ai_addr = (struct sockaddr *) sa;
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_canonname = ((char *) ai) +
sizeof(struct addrinfo) +
sizeof(struct sockaddr_in);
strcpy(ai->ai_canonname, canonname);

Thanks,
Everton

Eric Sosman 06-03-2004 03:44 PM

Re: Allocating single memory block for multiple structures
 
Everton da Silva Marques wrote:
> Hi,
>
> I need to allocate, using malloc(), a single
> memory block to hold two structures and a
> variable length string. Is it safe (portable,
> alignment-wise) to sum up the sizeof's of those
> structures and add the length of the string,
> as in this snippet?


No.

> const char *canonname = "domain.tld";
> struct addrinfo *ai;
> struct sockaddr_in *sa;
>
> ai = (struct addrinfo *) malloc(sizeof(struct addrinfo) +
> sizeof(struct sockaddr_in) +
> strlen(canonname) + 1);
>
> sa = (struct sockaddr_in *) (((char *) ai) + sizeof(struct addrinfo));


Here's the problem: A `struct sockaddr_in' might require
stricter alignment than a `struct addrinfo', so just sliding
forward by `sizeof(struct addrinfo)' bytes may not arrive at
an address where it's legitimate for a `struct sockaddr_in'
to begin.

> sa->sin_family = PF_INET;
> sa->sin_port = htons(80);
> sa->sin_addr.s_addr = INADDR_ANY;
>
> ai->ai_addr = (struct sockaddr *) sa;
> ai->ai_addrlen = sizeof(struct sockaddr_in);
> ai->ai_canonname = ((char *) ai) +
> sizeof(struct addrinfo) +
> sizeof(struct sockaddr_in);


You're safe on this one, though, because an array of
`char' can begin at any location without concern for
alignment issues.

> strcpy(ai->ai_canonname, canonname);


Although the code above is not portable and not safe,
there is a safe and portable and simple alternative:

struct addrstuff {
struct addrinfo ai;
struct sockaddr_in sa;
} *both;

both = malloc(sizeof *both + strlen(canonname) + 1);
if (both == NULL)
crash_and_burn();

both->sa.sin_family = PF_INET;
/* etc. */
both->ai.ai_addr = (struct sockaddr *) &both->sa;
/* etc. */
both->ai.ai_canonname = (char *)(both + 1);
strcpy (both->ai.ai_canonname, canonname);

Since the compiler knows the alignment requirement of
every type, it knows whether to insert padding bytes in
the middle of a `struct addrstuff' so that both elements
will be properly aligned.

It may also add padding at the very end of a `struct
addrstuff' so that everything would remain properly aligned
if you decided to allocate an array of them, but from your
point of view this is wasted space. It'll probably be a
small amount of waste, but if you Really Really want to
uglify the code to save those few bytes, you could write

both = malloc(offsetof(struct addrstuff, sa)
+ sizeof(struct sockaddr_in)
+ strlen(canonname) + 1);
...
both->ai.ai_canonname = (char*)(&both->sa + 1);

Personally, I don't think this is worth while nowadays.

--
Eric.Sosman@sun.com


Gordon Burditt 06-03-2004 04:23 PM

Re: Allocating single memory block for multiple structures
 
>I need to allocate, using malloc(), a single
>memory block to hold two structures and a
>variable length string. Is it safe (portable,
>alignment-wise) to sum up the sizeof's of those
>structures and add the length of the string,
>as in this snippet?


No. Consider what happens if you put the string, or a fixed-length
prime-length character array, FIRST. Chances are a struct following
it is going to be misaligned if it requires alignment at all.

There is no guarantee that a struct sockaddr_in doesn't require
stricter alignment than a struct addrinfo.

>
> const char *canonname = "domain.tld";
> struct addrinfo *ai;
> struct sockaddr_in *sa;
>
> ai = (struct addrinfo *) malloc(sizeof(struct addrinfo) +
> sizeof(struct sockaddr_in) +
> strlen(canonname) + 1);
>
> sa = (struct sockaddr_in *) (((char *) ai) + sizeof(struct addrinfo));
> sa->sin_family = PF_INET;
> sa->sin_port = htons(80);
> sa->sin_addr.s_addr = INADDR_ANY;
>
> ai->ai_addr = (struct sockaddr *) sa;
> ai->ai_addrlen = sizeof(struct sockaddr_in);
> ai->ai_canonname = ((char *) ai) +
> sizeof(struct addrinfo) +
> sizeof(struct sockaddr_in);
> strcpy(ai->ai_canonname, canonname);


Gordon L. Burditt

Everton da Silva Marques 06-03-2004 10:52 PM

Re: Allocating single memory block for multiple structures
 
Eric Sosman <Eric.Sosman@sun.com> wrote in message news:<40BF4777.3050807@sun.com>...
>
> Although the code above is not portable and not safe,
> there is a safe and portable and simple alternative:
>
> struct addrstuff {
> struct addrinfo ai;
> struct sockaddr_in sa;
> } *both;


In this example, is it safe to cast
(struct addrstuff *) to (struct addrinfo *),
so to access members in both->ai ?
Like this:

struct addrinfo *ai = (struct addrinfo *) both;
ai->ai_addr = ...

I mean:

1) is member ordering guaranteed in struct's ?
2) does the first member always align at
the begining of the struct?

BTW, awesome answer, thanks!

--
Everton

Sam Dennis 06-04-2004 01:41 AM

Re: Allocating single memory block for multiple structures
 
Everton da Silva Marques wrote:
> Eric Sosman <Eric.Sosman@sun.com> wrote in message news:<40BF4777.3050807@sun.com>...
>> struct addrstuff {
>> struct addrinfo ai;
>> struct sockaddr_in sa;
>> } *both;

>
> In this example, is it safe to cast (struct addrstuff *) to (struct
> addrinfo *), so to access members in both->ai ?


Yes, but wholly unnecessary and a possible cause of trouble in the
future, as you might decide to change the order of the structure's
members later.

> struct addrinfo *ai = (struct addrinfo *) both;
> ai->ai_addr = ...


both->ai.ai_addr = ...

> 1) is member ordering guaranteed in struct's ?


Yes, basically.

--
++acr@,ka"

J. J. Farrell 06-04-2004 03:23 AM

Re: Allocating single memory block for multiple structures
 
evertonsm@yahoo.com.br (Everton da Silva Marques) wrote in message news:<cc8d795c.0406031452.eacc168@posting.google.c om>...
> Eric Sosman <Eric.Sosman@sun.com> wrote in message news:<40BF4777.3050807@sun.com>...
> >
> > Although the code above is not portable and not safe,
> > there is a safe and portable and simple alternative:
> >
> > struct addrstuff {
> > struct addrinfo ai;
> > struct sockaddr_in sa;
> > } *both;

>
> In this example, is it safe to cast
> (struct addrstuff *) to (struct addrinfo *),
> so to access members in both->ai ?
> Like this:
>
> struct addrinfo *ai = (struct addrinfo *) both;
> ai->ai_addr = ...


Yes.

> I mean:
>
> 1) is member ordering guaranteed in struct's ?


Yes.

> 2) does the first member always align at
> the begining of the struct?


Yes.

xarax 06-04-2004 03:26 AM

Re: Allocating single memory block for multiple structures
 
"Gordon Burditt" <gordonb.5gzqt@burditt.org> wrote in message
news:c9njah$qa2@library2.airnews.net...
> >I need to allocate, using malloc(), a single
> >memory block to hold two structures and a
> >variable length string. Is it safe (portable,
> >alignment-wise) to sum up the sizeof's of those
> >structures and add the length of the string,
> >as in this snippet?

>
> No. Consider what happens if you put the string, or a fixed-length
> prime-length character array, FIRST. Chances are a struct following
> it is going to be misaligned if it requires alignment at all.
>
> There is no guarantee that a struct sockaddr_in doesn't require
> stricter alignment than a struct addrinfo.

/snip/

You will need to calculate the alignment of
each struct, and then calculate the offset
of the next location that is compatible with
that alignment.

You can use a macro like this to calculate
the alignment of a type X:

#define alignof(X) (sizeof(struct{X a;char b})-sizeof(struct{X a;}))

The parameter X is a type name (usually a typedef name
or a type name that is syntactically correct for the
macro expansion). The macro will expand to a constant
expression. Some compilers, like M$ visual C++ will
issue a warning about the unnamed struct, but just turn
off that stupid warning.





All times are GMT. The time now is 09:13 AM.

Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57