Sizeof

El operador sizeof retorna la cantidad de bytes del parámetro.

Por definición, sizeof(char) es 1. Para otros objetos el valor puede variar.

Es común sizeof(int) que de 4 pero depende de la arquitectura y del compilador. Si se quiere un entero que siempre tenga 4 bytes se puede usar int32_t.

sizeof no es una función sino un operador que se evalua en tiempo de compilación.

De hecho, sizeof puede resolver tanto sobre tipos como sobre variables y atributos. En todos los casos retorna el tamaño del parámetro.

Ejemplos:
size_t a = sizeof(char);  // size del tipo char

int x;
size_t b = sizeof(x);   // size del tipo de la variable x (int)

struct foo_t f;
size_t c = sizeof(struct foo_t); // size de la estructura
size_t d = sizeof(f);   // equivalente al anterior

size_t e = sizeof(f.bar);   // size del tipo del atributo bar

El tamaño de una estructura no necesariamente es la suma de los tamaños de sus atributos. Esto se debe a que el compilador puede alinear los atributos al tamaño de la palabra o del tipo nativo (escalar) más grande de la estructura y agregar padding entre los atributos, lo que alarga a la estructura.

Aun asi hay que tomar en cuenta que depende de la arquitectura.

Por ejemplo:

struct foo_t {
    int i;
    uint64_t j;
};

Compilado con GCC en 64 bits da un sizeof(struct foo_t) de 16 bytes (4 + padding + 8) mientras que en 32 bits da 12 bytes (4 + 8).

Alineación, padding y el tamaño de la palabra dependen de la arquitectura y del compilador.