![]() |
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 |
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 |
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 |
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 |
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" |
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. |
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.