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);

    Everton da Silva Marques, Jun 3, 2004
    1. Advertisements

  2. Everton da Silva Marques

    Eric Sosman Guest

    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.
    You're safe on this one, though, because an array of
    `char' can begin at any location without concern for
    alignment issues.
    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)

    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
    1. Advertisements

  3. I need to allocate, using malloc(), a single
    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.
    Gordon L. Burditt
    Gordon Burditt, Jun 3, 2004
  4. 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 da Silva Marques, Jun 3, 2004
  5. Everton da Silva Marques

    Sam Dennis Guest

    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.
    both->ai.ai_addr = ...
    Yes, basically.
    Sam Dennis, Jun 4, 2004
  6. Yes.
    J. J. Farrell, Jun 4, 2004
  7. Everton da Silva Marques

    xarax Guest


    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
    1. Advertisements

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.