Data Types in C Explained: Ranges, Conversions and Worked Exam Examples

Learn how C types control ranges and conversions, then apply the rules to overflow, mixed arithmetic, sizeof and signed-unsigned exam questions.

KnowledgeGate Team

Exam prep & CS education

Updated 3 Sep 20266 min read

A C declaration may look simple, but its type controls the value range, arithmetic conversions and even whether an overflow has a defined result. Portable reasoning separates the C standard's guarantees from machine-specific assumptions, then classifies each operand and evaluates expressions in the order C requires. Three mechanisms do most of that work: the conversion ranks that decide which operand moves, the <limits.h> guarantees that survive a change of machine, and the signed-versus-unsigned comparison that turns -1 into a value larger than 1.

Data types in C: what a declaration tells the compiler

A data type determines a value's domain, representation constraints, permitted operations and conversion behaviour. Consider _Bool ready = 1;, char grade = 'A';, int count = 42;, unsigned int mask = 255u;, float temperature = 36.5f; and double mean = 2.75;.

C's arithmetic types include integers and real floating types. void represents no value, while enumerations name integral constants. Pointers, arrays, functions, structures and unions build other forms. A typedef gives an existing type another name, not a new range or representation.

A variable's declared type and a literal's type are separate. 42 is int, 42u is unsigned int, 2.75 is double, and 2.75f is float. These suffixes can change an expression's conversions.

A C type map sorting example declarations into arithmetic, void, enum, pointer, array, function, structure and union groups.

C integer types and modifiers: start with portable guarantees

The integer family contains _Bool; distinct char, signed char and unsigned char types; and signed or unsigned short, int, long and long long. _Bool ranks below the three character types, which share a rank. Signed ranks then rise through short, int, long and long long; each corresponding unsigned type shares that rank.

The portable size relationship is:

sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)

Equality is allowed. Plain char is distinct, and whether its values behave like signed char or unsigned char is implementation-defined. sizeof(char) is always 1 C byte, but a byte need not be eight bits. <limits.h> provides CHAR_BIT and the actual limits.

Assume CHAR_BIT = 8, an 8-bit unsigned char, a 32-bit two's-complement int with no padding bits, and a 32-bit unsigned int with no padding bits. An N-bit unsigned type ranges from 0 to 2^N - 1; a two's-complement signed type ranges from -2^(N-1) to 2^(N-1) - 1. Review the powers in Number Systems and Base Conversions Explained.

Those assumptions give:

Type

Calculation

Range

unsigned char

0 to 2^8 - 1

0 to 255

int

-2^31 to 2^31 - 1

-2,147,483,648 to 2,147,483,647

unsigned int

0 to 2^32 - 1

0 to 4,294,967,295

Exact-width names such as uint8_t and int32_t come from <stdint.h>, but each is available only when the implementation provides that exact width.

Floating types in C: range, precision and suffixes

C provides float, double and long double. The standard fixes no width for them, only a floor, and <float.h> names every limit. A conforming float keeps at least 6 decimal digits of precision (FLT_DIG) and covers magnitudes from at least 1E-37 to 1E+37; a conforming double keeps at least 10 digits (DBL_DIG) across that same guaranteed span. Those floors, not any byte count, are what portable code may rely on.

On common IEEE 754 implementations, float is binary32 with a 24-bit significand and double is binary64 with a 53-bit significand. Such an implementation reports FLT_DIG as 6 and DBL_DIG as 15, so digits printed beyond those counts say nothing reliable about the stored value.

Precision is not exactness. In float f = 0.1f; the literal is float, and in double d = 0.1; it is double, but neither stores 0.1 exactly, because 0.1 has no finite binary fraction. The printed tail depends on the implementation and the format string. Floating Point Representation: IEEE 754 Format explains sign, exponent and fraction fields.

Compare floating results with an absolute or relative tolerance suited to their scale rather than with ==. For a data-type question, identify the literal's type first, then the conversion that type triggers.

Integer promotions and usual arithmetic conversions

Precedence forms operations, integer promotions lift small types, and the usual arithmetic conversions choose a common type for each binary operation. C does not convert everything once to the largest-looking declaration.

With those assumptions, evaluate:

unsigned char u = 250; int n = 10; float f = 7.5f; double d = 2.0;

double answer = u + n * f / d;

  1. Multiplication comes before addition. For n * f, n converts from int 10 to float 10.0f.

  2. 10.0f * 7.5f produces 75.0f.

  3. For division by d, 75.0f converts to double 75.0. Then 75.0 / 2.0 produces 37.5.

  4. u is integer-promoted to int 250, then converted to double 250.0 for the addition.

  5. 250.0 + 37.5 gives 287.5, of type double.

The answer is not 287, and u does not wrap because nothing is assigned back to unsigned char.

A conversion pipeline for u + n * f / d showing 10 to 10.0f, 75.0f to 75.0, 75.0 / 2.0 = 37.5 and a final 287.5 of type double.

C overflow, narrowing and integer division

With those assumptions, take unsigned char c = 250; c = c + 10;. Promotion makes c + 10 an int: 250 + 10 = 260. Conversion back reduces 260 modulo 256, so 260 - 256 = 4. This unsigned conversion is well-defined. Signed integer overflow has undefined behaviour, not automatic wraparound.

The destination does not retroactively change the right-hand expression:

  • double a = 5 / 2; performs integer division first, producing 2, then stores 2.0.

  • double b = 5.0 / 2; converts 2 for floating division and stores 2.5.

An explicit conversion to integer discards the fractional part towards zero. Thus (int)7.9 is 7, while (int)-7.9 is -7. Converting a floating value outside the destination integer's range is not a safe portable shortcut.

sizeof, arrays and format specifiers

With an 8-bit byte and 32-bit int, int values[5] = {2, 4, 6, 8, 10}; occupies 5 * sizeof(int) = 5 * 4 = 20 bytes where values is an array. In a function parameter, int values[] is adjusted to int *, so sizeof(values) measures the pointer, not the original array. Those assumptions do not determine a pointer size.

In C, the character constant 'A' has type int, so sizeof('A') == sizeof(int). The string literal "A" is an array containing 'A' and '\0', so sizeof("A") == 2.

Function

Value or pointer type

Correct specifier

printf

int

%d

printf

unsigned int

%u

printf

float, promoted to double

%f

printf

size_t

%zu

scanf

float *

%f

scanf

double *

%lf

A mismatched format is a type error that can cause undefined behaviour, not a cosmetic display issue.

How exams test C data type fundamentals

Recurring patterns include suffixes, sizeof, promotions, signed-versus-unsigned comparison, integer division and narrowing. Separate well-defined unsigned conversion, implementation-defined plain-char signedness and undefined signed overflow. The KnowledgeGate practice bank carries over 40 questions on C data-type fundamentals, giving you enough material to practise those distinctions repeatedly.

With the same machine model, solve int s = -1; unsigned int v = 1u; int result = (s < v);. The operands have the same rank, but one is unsigned. Since the 32-bit int cannot represent every 32-bit unsigned int value, s converts to unsigned int. The value -1 becomes 4,294,967,295. That is not less than 1, so the comparison is false and result is 0.

Two quick checks follow the same discipline. sizeof(3.14) asks for the size of double, while sizeof(3.14f) asks for the size of float. double x = 7 / 2; stores 3.0, not 3.5. Use the GATE CS Exam Preparation page to place these questions inside wider subject preparation.

Data types in C: the short version and next step

Use this five-step checklist:

  1. Identify every operand's type.

  2. Apply precedence to form the operations.

  3. Perform integer promotions.

  4. Apply the usual arithmetic conversions to each operation.

  5. Check the final destination conversion.

For portable code, consult <limits.h>, <stdint.h> and <float.h> instead of memorising one compiler's table. If you need the full language sequence, continue with the C Language course. If you are preparing for GATE and want data types inside a complete CS plan, use GATE Guidance by Sanchit Sir.

Once you track operand types and conversions in order, data-type questions become calculations rather than guesses.