Question bank — Type sizes — sizeof, platform dependency, stdint.h (int32_t etc.)
This bank is deliberately non-computational — there is no arithmetic to grind. Every item is about whether a belief is true and why. The word "justify" is not optional: a bare "true/false" earns nothing, because the whole skill is the reasoning that survives when you switch machines.
True or false — justify
C guarantees int is exactly 4 bytes on every hosted platform.
int is at least 16 bits; 4 bytes is a mainstream 32/64-bit coincidence, and 16-bit targets use 2-byte int.sizeof(char) can legally be 2 on some machine.
sizeof counts in units of char, and a char is "1 char" by definition — so sizeof(char) is 1 on every conforming implementation, always.A char is guaranteed to be exactly 8 bits.
char is at least 8 bits (CHAR_BIT ≥ 8); rare DSPs use larger char. It's sizeof(char)==1 that's guaranteed, not "8 bits".On 64-bit Windows, sizeof(long) == sizeof(long long).
long is 4 bytes and long long is 8, so they differ. They'd only match on LP64 (Linux/macOS 64-bit).If two types have the same sizeof, they represent the same set of values.
int and unsigned int share a size but hold different ranges (one signed, one unsigned), and int vs float share 4 bytes yet encode numbers completely differently. See Two's complement & integer overflow.sizeof(void*) == sizeof(int) on all platforms.
int is 4. Storing a pointer in an int truncates it — use intptr_t if you must.int32_t is guaranteed to exist on every conforming compiler.
int32_t is only defined if the platform has an exact 32-bit two's-complement type. int_least32_t and int_fast32_t are the ones that are always available.The size ordering char ≤ short ≤ int ≤ long ≤ long long is guaranteed.
int can never be strictly wider than long.sizeof evaluates its operand at run time.
sizeof is a compile-time operator; the size is fixed when compiling. (The one exception is variable-length arrays, which most style guides avoid.)Spot the error
printf("%d\n", sizeof(int));::: Wrong specifier. sizeof yields size_t (unsigned, often 64-bit); printing it with %d is undefined behavior. Use %zu. See printf format specifiers.
int count = sizeof(arr) / sizeof(arr[0]); // arr is a function parameter::: Inside a function, an array parameter decays to a pointer (Pointers and array decay), so sizeof(arr) is the pointer size, not the array size — the count is wrong. Pass the length as a separate argument.
unsigned char *img = malloc(1024);
long total = sizeof(img); // "bytes I allocated"::: sizeof(img) is the size of the pointer (8 bytes on 64-bit), not the 1024 bytes it points at. sizeof never knows how big a malloc'd block is; you must track that yourself.
struct Packet { uint16_t port; uint32_t ip; };
// assume sizeof(Packet) == 6::: Wrong: alignment forces padding. The compiler likely inserts 2 bytes so ip sits on a 4-byte boundary, giving sizeof == 8. Fixed-width members do not remove padding — see Struct padding & alignment.
char c = getchar();
if (c == EOF) { /* done */ }::: If plain char is unsigned on this platform, it can never equal EOF (a negative int), so the loop never ends. getchar returns int for exactly this reason — store it in an int.
char b = 200; // hold a byte value::: On a signed-char platform, 200 overflows the signed range and stores a negative value. For a raw 0–255 byte, use unsigned char or uint8_t.
Why questions
Why does C leave int's size unspecified instead of just fixing it at 4?
Why is sizeof(char) defined to be 1 rather than "8 bits"?
sizeof is a ratio of storage to char-storage; making char the unit means all other sizes are counted in chars, so char itself is trivially 1.Why must you send network/file-format structs with int32_t instead of int?
int/long differ across ABIs, so two machines would disagree on the layout; int32_t pins it. See Endianness & serializing data.Why does sizeof a / sizeof a[0] give the element count portably?
char-size cancels and the answer never depends on how wide int happens to be.Why does sizeof return size_t rather than int?
INT_MAX bytes; size_t is an unsigned type guaranteed big enough to hold any object's size. More on size_t and ptrdiff_t.Why is long the classic portability landmine and not int?
int is 4 bytes on essentially every 32/64-bit desktop, but long splits: 8 on Linux/macOS, 4 on Windows. Same source, different width, silent bug.Why prefer uint8_t over plain char for raw bytes?
char's signedness is implementation-defined, so bit-twiddling and comparisons behave differently per platform; uint8_t is unambiguously 0–255.Edge cases
What is sizeof(sizeof(int))?
sizeof(size_t) — because sizeof(int) has type size_t. So it's the size of size_t itself (typically 8 on 64-bit), not related to int.Does sizeof on a bit-field like x:3 give a fraction?
sizeof never sees a bit-field; you can't even apply it to one. sizeof only measures whole objects/types in whole char units.On a 16-bit machine where int is 2 bytes, is int32_t still 4 bytes?
int. The compiler builds int32_t from whatever type is exactly 32 bits (here, long).Can sizeof(struct S) be smaller than the sum of its members' sizes?
If CHAR_BIT were 16, would int32_t still be 4 chars wide?
int32_t is exactly 32 bits; with 16-bit chars that's 32/16 = 2 chars, so sizeof(int32_t) would be 2. The name promises bits, and sizeof counts chars.Is sizeof(x) where x is undeclared a compile error?
sizeof needs a known type, so an undeclared name fails to compile. But sizeof never reads a valid x, so sizeof(*p) is fine even when p is a null pointer.Recall
Recall The single sentence that prevents most portability bugs
"Plain int/long promise a minimum, never an exact width — if I need exact bytes I write the number: int32_t."