Allocating single memory block for multiple structures

Discussion in 'C Programming' started by Everton da Silva Marques, Jun 3, 2004.

  1. 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
    Everton da Silva Marques, Jun 3, 2004
    #1
    1. Advertising

  2. Everton da Silva Marques

    Eric Sosman Guest

    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, Jun 3, 2004
    #2
    1. Advertising

  3. >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
    Gordon Burditt, Jun 3, 2004
    #3
  4. Eric Sosman <> wrote in message news:<>...
    >
    > 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
    Everton da Silva Marques, Jun 3, 2004
    #4
  5. Everton da Silva Marques

    Sam Dennis Guest

    Everton da Silva Marques wrote:
    > Eric Sosman <> wrote in message news:<>...
    >> 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"
    Sam Dennis, Jun 4, 2004
    #5
  6. (Everton da Silva Marques) wrote in message news:<>...
    > Eric Sosman <> wrote in message news:<>...
    > >
    > > 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.
    J. J. Farrell, Jun 4, 2004
    #6
  7. Everton da Silva Marques

    xarax Guest

    "Gordon Burditt" <> wrote in message
    news:c9njah$...
    > >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.
    xarax, Jun 4, 2004
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. morrell
    Replies:
    1
    Views:
    934
    roy axenov
    Oct 10, 2006
  2. Alfonso Morra
    Replies:
    11
    Views:
    702
    Emmanuel Delahaye
    Sep 24, 2005
  3. Amit_Basnak
    Replies:
    3
    Views:
    800
  4. Rakesh Kumar
    Replies:
    5
    Views:
    671
    James Kanze
    Dec 21, 2007
  5. Water Cooler v2
    Replies:
    2
    Views:
    446
    Water Cooler v2
    Apr 18, 2006
Loading...

Share This Page