Introduction
C is a small, statically typed, compiled language in which the programmer works close to the machine: every object has a type that fixes how many bytes it occupies and how those bytes are interpreted. Predicting what a C program prints depends, nearly every time, on two things introduced here: how a C program is put together, and exactly what values each basic type can hold.
This note fixes the conventions used by every C note in this subject.
- Standard. C11 (ISO/IEC 9899:2011), hosted implementation (a normal operating system with the full standard library).
- Data model for examples. Unless a question states otherwise, examples assume LP64, the model of 64-bit Linux and macOS with gcc or clang:
char1 byte,short2,int4,long8,long long8, pointers 8, and two's complement integers. The other common model, ILP32 (32-bit systems), differs only inlongand pointers being 4 bytes. Windows 64-bit uses LLP64 (long4 bytes, pointers 8). - GATE convention. When a question gives sizes ("assume
intis 4 bytes"), use them; they override everything here.
Prerequisites
- Signed Number Representation: two's complement, needed for integer ranges and overflow.
- Basic binary and hexadecimal: Number Systems.
Core concepts
Structure of a C program
A C program is one or more translation units (a source file after preprocessing), compiled separately and then linked. A minimal hosted program:
#include <stdio.h> /* preprocessor directive: textual inclusion */
#define N 3 /* macro: replaced before compilation */
int square(int x); /* declaration (prototype) */
int main(void) { /* execution starts here */
int total = 0; /* definition with initialisation */
for (int i = 1; i <= N; i++)
total += square(i);
printf("sum of squares = %d\n", total);
return 0; /* 0 means success to the host */
}
int square(int x) { return x * x; } /* definition */Output: sum of squares = 14.
The pieces, in the order the toolchain sees them:
- Preprocessing. Lines starting with
#are handled first:#includepastes a header,#definesets up text replacement. See The C Preprocessor. - Compilation. Each translation unit becomes an object file. A function must be declared before it is called; the prototype
int square(int x);letsmaincallsquare, which is defined later. - Linking. Object files and the library are joined; every function or object that is used must be defined exactly once in the whole program.
- Execution starts at
main. In a hosted implementation the two portable forms areint main(void)andint main(int argc, char *argv[]). Reaching the closing brace ofmainis equivalent toreturn 0;(C99 onward), but only formain.
Declaration versus definition. A declaration announces a name and its type. A definition also creates the object (allocates storage) or supplies the function body. extern int count; is a declaration only; int count = 5; at file scope is a definition. The details are in Scope, Storage Classes and Linkage.
Tokens: identifiers, keywords and constants
- Identifiers consist of letters, digits and underscores and must not start with a digit. They are case-sensitive:
Countandcountare different. Names beginning with an underscore followed by an uppercase letter or a second underscore are reserved for the implementation. - Keywords are reserved words that cannot be identifiers. C11 has 44 of them, from
autoandbreakto_Static_assertand_Thread_local. Note thatmain,printfandNULLare not keywords. - Comments
/* ... */do not nest;//comments run to the end of the line (C99 onward). Comments are replaced by a single space before preprocessing directives are executed.
The basic types
C has integer types, floating types and void. Their sizes are not fixed by the standard; only minimum ranges and an ordering are guaranteed.
| Type | Minimum range guaranteed by C11 (limits.h) | Typical size, LP64 |
|---|---|---|
signed char | to | 1 byte |
unsigned char | to | 1 byte |
short | to | 2 bytes |
int | to | 4 bytes |
long | to | 8 bytes |
long long | to | 8 bytes |
float | at least 6 significant decimal digits (FLT_DIG) | 4 bytes |
double | at least 10 significant decimal digits (DBL_DIG) | 8 bytes |
Guarantees that hold on every conforming implementation:
sizeof(char) == 1by definition. A "byte" in C isCHAR_BITbits, at least 8.- .
- Each signed type has an unsigned counterpart of the same size.
- Whether plain
charis signed or unsigned is implementation-defined. On x86 gcc it is signed (range to ); on ARM Linux it is unsigned.char,signed charandunsigned charare three distinct types.
The minimum ranges look one short on the negative side (, not ) because C11 still permits sign-and-magnitude and ones' complement representations. Every real machine uses two's complement, and C23 makes it mandatory.

Ranges from the bit width
For an -bit integer type:
Here sizeof(type) when CHAR_BIT is 8. With : unsigned 0 to 255, signed to 127. With : unsigned 0 to 4294967295, signed to 2147483647. The signed range is asymmetric: there is one more negative value than positive.
Constants and their types
Every constant has a type, and the type decides the arithmetic.
- Integer constants. Decimal
42, octal052(leading zero), hexadecimal0x2A. All three are the value 42.08is a compile error, because 8 is not an octal digit. A decimal constant without suffix gets the first ofint,long,long longthat can hold it; octal and hexadecimal constants may also become unsigned types. Suffixes:U(unsigned),L(long),LL(long long), combinable asUL,ULL. - Floating constants.
1.5,2e-3,.5have typedouble. Suffixfgivesfloat,Lgiveslong double. Sosizeof 1.5is 8 butsizeof 1.5fis 4. - Character constants.
'A'has typeintin C (notchar, unlike C++), sosizeof('a') == sizeof(int), which is 4 under LP64. Its value is the character's code: 65 in ASCII. Escape sequences include'\n','\t','\0'(value 0),'\\','\'', octal'\101'and hex'\x41'(both 65). - String literals.
"abc"is an array of 4char(the 3 characters plus the terminating'\0'), sosizeof "abc"is 4. Modifying a string literal is undefined behaviour. See Strings.
Character arithmetic
Because characters are small integers, arithmetic on them is ordinary integer arithmetic. In ASCII the digits '0' to '9' are consecutive (C guarantees this for digits in every character set), so '9' - '0' is 9 and '0' + 7 is 55, the code of '7'. The letters are consecutive in ASCII but this is not guaranteed by C, so 'A' + 2 == 'C' is true under ASCII only.
Integer division and remainder
Since C99, integer division truncates toward zero, and the remainder satisfies
so the remainder takes the sign of the dividend . Examples: 7/2 is 3, -7/2 is , 7/-2 is ; 7%3 is 1, -7%3 is , 7%-3 is 1. Division or remainder by zero is undefined behaviour, and so is INT_MIN / -1 (the result does not fit). The operands of % must be integers.
Unsigned wrap-around versus signed overflow
- Unsigned arithmetic is performed modulo .
unsigned int u = 0; u = u - 1;gives 4294967295 for a 32-bitunsigned int. This is well defined. - Signed overflow (a result outside the type's range, such as
INT_MAX + 1) is undefined behaviour. It is not "wrap to negative"; the compiler may assume it never happens. See Undefined, Unspecified and Implementation-Defined Behaviour. - Integer-to-integer conversion. Conversion to an unsigned type reduces modulo one more than that type's maximum value; with an 8-bit unsigned char, 255 plus 1 stores 0. An unrepresentable integer converted to a signed integer type has an implementation-defined result or raises an implementation-defined signal. This is not the floating-to-integer rule: finite floating values truncate toward zero, and an unrepresentable integral part makes the conversion undefined. See Type Conversions.
Floating-point values
On essentially every current system float and double are IEEE 754 binary32 and binary64. Most decimal fractions, such as 0.1, are not exactly representable, so the stored value is the nearest binary fraction. Consequences:
float f = 0.1f;thenf == 0.1is false (0):fis converted todoublefor the comparison, but thefloatapproximation of 0.1 differs from thedoubleapproximation.f == 0.1fis true.- For inexact computations where approximate numerical agreement is intended, choose a suitable absolute/relative tolerance rather than blindly testing equality; exact equality is valid when the specification calls for it.
- Mixed expressions convert to the wider floating type:
5 / 2 * 2.0is2 * 2.0, which is 4.0, because5 / 2is integer division done first.5 / 2.0 * 2is 5.0.
Representation details belong to Floating-Point Representation.
sizeof
sizeof is an operator, not a function. It yields a value of type size_t (an unsigned integer type) and is normally evaluated at compile time. Its operand is not evaluated (the one exception is a variable length array): after int i = 5; size_t s = sizeof(i++);, i is still 5 and s is 4. Parentheses are required only for a type name: sizeof(int) but sizeof x. Print a size_t with %zu.
printf and scanf format specifiers
| Specifier | Type expected by printf |
|---|---|
%d, %i | int |
%u, %x, %o | unsigned int (decimal, hex, octal) |
%ld, %lld | long, long long |
%c | int (printed as a character) |
%f, %e, %g | double (a float argument is promoted to double) |
%s | char * to a null-terminated string |
%p | void * |
%zu | size_t |
A specifier that does not match the type of the argument is undefined behaviour (for example printf("%d", 3.5)). scanf needs addresses: scanf("%d", &x), and %f in scanf means float * while %lf means double *.
Worked examples
All outputs below are for C11 with gcc on x86-64 Linux (LP64).
Example 1 (sizes). printf("%zu %zu %zu %zu", sizeof(int), sizeof(long), sizeof(void*), sizeof('a')); prints 4 8 8 4. Under ILP32 it would print 4 4 4 4.
Example 2 (constants). printf("%d %d %d %d", 010, 0x1F, 'A' + 1, '0' + 7); prints 8 31 66 55. The leading zero makes 010 octal.
Example 3 (division). printf("%d %d %d", -7/2, -7%3, 7%-3); prints -3 -1 1. Check with : is the quotient-remainder pair for ; for , .
Example 4 (wrap-around and floats).
unsigned char c = 255; c = c + 1; /* c becomes 0 */
unsigned int u = 0; u = u - 1; /* u becomes 4294967295 */
float f = 0.1f;
printf("%d %u %d %d\n", c, u, f == 0.1, f == 0.1f);prints 0 4294967295 0 1.
Example 5 (mixed arithmetic). printf("%.1f %d", 5 / 2 * 2.0, (int)(5 / 2.0 * 2)); prints 4.0 5.
Important properties and observations
- Sizes are implementation-defined; only minimum ranges and ordering are guaranteed. Always state or read the data model.
'a'is anintin C.sizeof('a')issizeof(int), not 1.- A leading zero makes an integer constant octal;
08and09do not compile. - Integer division truncates toward zero; the remainder has the sign of the dividend.
- Unsigned arithmetic wraps modulo ; signed overflow is undefined behaviour.
- The signedness of plain
charis implementation-defined. - The operand of
sizeofis not evaluated (except for variable length arrays). - Floating constants are
doubleunless suffixed withf.
GATE examination perspective
- Output prediction. Most C questions ask for printed output. Track each variable's type first, then its value; type decides whether
/truncates, whether a value wraps and howprintfprints it. - Stated sizes. If the question says
intis 2 bytes, the range is to (two's complement) and32767 + 1inintis overflow. - Octal trap.
int a = 012;is 10, not 12. - Character trap.
printf("%d", 'A')prints 65;printf("%c", 65)printsA. - Floating comparison trap.
float x = 0.1; if (x == 0.1)is false; with 0.5 or 0.25 (exactly representable) it is true. - Division trap.
3/2*2is 2, while3*2/2is 3.
Summary
Sources
- ISO/IEC 9899:2011 (C11), committee draft N1570, (consulted 2026-11-09), Sections 5.1.2.2 (hosted environment, main), 5.2.4.2.1 (sizes of integer types, limits.h), 5.2.4.2.2 (float.h), 6.2.5 (types), 6.4.1 (keywords), 6.4.4 (constants), 6.5.3.4 (sizeof), 6.5.5 (multiplicative operators), 6.3.1.3 (signed and unsigned integer conversions).
- B. W. Kernighan and D. M. Ritchie, The C Programming Language, 2nd ed., Prentice Hall, 1988: Chapter 1 (a tutorial introduction) and Chapter 2 (types, operators and expressions).