Search code examples
cbinary-treepreorder

Are there zero bytes after a `char` in a struct?


I'm trying to make sure I understand what the hidden assumptions here are.

This code here gives correct results.

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

struct branch
{
    char flag;      //value
    struct branch *l; //left child
    struct branch *r; //right child
};

struct branch c={'c',NULL,NULL};
struct branch e={'e',NULL,NULL};
struct branch f={'f',NULL,NULL};
struct branch b={'b',&c,NULL};
struct branch d={'d',&e,&f};
struct branch a={'a',&b,&d};

void preorder(struct branch* t)
{
    printf(&t->flag);    //Seems ugly and errorprone
    if(t->l) preorder(t->l);
    if(t->r) preorder(t->r);
}

int main()
{
    preorder(&a);
}

Output, as expected, is abcdef

Can someone confirm my suspicions, that this only works because two things:

  1. struct members get aligned at n-byte boundaries (n != 1)(n = 4, it seems, when asking sizeof()-s)
  2. bytes not used by the first member (which is a char) up to the n-byte boundary are zeroed.

I see no other explanation for printf working correctly otherwise, as it expects a zero-terminated char[].

Furthermore, is it wise to do things like that (outside of a single-target embedded code situation, where the optimisation may outweigh the readability and portability issues), ie. are these assumptions more-or-less universally true?

First week of intermittently messing with C, so I'm pretty green.


Solution

  • To verify your assumptions, you can inspect the code at runtime with a debugger or by using some printf.

    For example, with:

      char *ptr=(char *)&t;
      printf("%02X %02X %02X %02X\n",ptr[0],ptr[1],ptr[2],ptr[3]);
    

    Indeed the assumptions you identified are very often true, but you can't rely on them. I definitely would say that

      printf(&t->flag);
    

    is plainly wrong because it relies on assumptions that are not guaranteed by the standard.tt