Table of Contents
Introduction
Basic Data Types Used In C Language:
Character Data Type
Character types (char) typically used to store single ASCII character value and numbers. Char can store 1 byte (1 byte = 8 bits = 2 nibbles). There are 8 positions to place 1s and 0s, so we can make \({2}^{8}= 256\) different values. A char data type can store numbers from 0 to 255 unsigned (positive numbers) and -128 to 127 signed numbers. Char data types also used to store ASCII characters which are represented as integer values ranging from 0 to 127 using 7 bits. Left most 8th bit is used in extended ASCII and as parity bit in some systems. ASCII characters are written in ‘ ‘ e.g. character ‘A’ has ASCII value 65 . Numbers are written without ‘ ‘.
Integer Data Type
Before going to understand int data type we have to understand bit architecture. Bit architecture refers to the size of CPU registers( these are temporary storage inside the CPU e.g. General purpose registers , flag registers etc), memory addressing and data processing units within a computer. CPU’s bit architecture defines how many bits it can process at a time. A older version operating systems like windows XP or windows 95 have 32 bit architecture, it means it can process 32 bits at a time and it can address maximum \( {2}^{32} = 4\)GB of RAM. Data bus width in a 32 bit architecture can fetch, read and write 32bits or 4 bytes chunks of data in a single operation. Similarly in a 64 bit modern architecture a CPU can process 64 bits at time and address up to \({2}^{64} = 18.4 milion \)TB of RAM. Char is always 1 byte in 32 bit and 64 bit architecture but int may vary. We have different int data types in c, whose sizes vary in different architecture e.g. int in 16 bit architecture is 2 bytes but int in 32 bit architecture it is 4 bytes. That means in 16 bit architecture unsigned int can range from 0 to 65535 (\({2}^{16} = 65536\)) i.e. if we take a variable e.g. unsigned int a = 65678; then it will cause overflow error because \(65678 > 65536\). But int in 32 bit architecture unsigned int can range 0 to 4294967295 (\({2}^{32 }= 4294967296\)). Like this we have data types short int , long int , long long int etc.
Float Data Type
Float data type usually used to store fractional and decimal values. Float is always 4 bytes in 32 bit and 64 bit architecture. It follows the IEEE 754 standard for 32 bit single precision floating point representation, we have described IEEE 754 standard in detail in this blog. In IEEE 754 32 bit single precision floating point is consist of 1 sign bit + 8 bit exponent + 23 bit mantissa or significand = 32 bit and (1.) implicitly there to satisfy normalized form.
Now we will find range of float data type, for maximum value of float, sign bit is 0 for positive, exponent is 8 bit so we can store \({2}^{8} = 256\) different decimal (0 to 255) as binary in exponent, but here actual exponent = stored exponent – 127(bias), means actual exponent = \(254-127=127\) which is used in calculation and stored exponent is the binary value stored in the exponent field. Exponent=0, is used in subnormal numbers, which we will study in this section. Exponent=255, is use for infinity or NaN. Largest mantissa is all 1s i.e. 1.11111111111111111111111 (1. followed by 23 1s ). Then normalize it to scientific notation i.e. \(1.xxxx \times 2^n\), i.e. \(1.11111111111111111111111 \times 2^{127}\), now we convert the mantissa to decimal to decimal, we have explained how to convert mantissa to decimal in this blog. \(1 + 1\times 2^{-1} + 1 \times 2^{-2 }+…..+ 1 \times 2^{-23} = 1 + \frac{1}{2} + \frac{1}{4} +….+ \frac{1}{2^{23}} \), this is geometric series so according to geometric series formula \[S_n = a + ar + ar^2 + \cdots + ar^{n-1} = a \cdot \frac{1 – r^n}{1 – r} \quad \text{for } r \ne 1\]
a=1(first term), \(r=\frac{1}{2}\) (common ratio), n=24 (no. of terms), after solving we get \(2 – 2\times (\frac{1}{2^{24}}) = 2 – 2^{-23}\). So now we write \((2-2^{-23}) \times 2^{127} \)in normalized form, which is nearly equal to \(3.4028235 \times 10^{38}\) which is maximum value of float means it is farthest point in positive direction in a number line. Maximum and most negative float is \(-3.4028235 \times 10^{38} \)think it as it is farthest point in negative direction in a number line.
Now we will see smallest positive value of float in normalized form, sign bit is 0, exponent is decimal 1 which is in binary 0000_0001, actual exponent which will use for calculation to normalized form is \(1-127=-126\), mantissa is all 0s with implicit (1.). Now we put these in normalized form \(1.00000000000000000000000 \times 2^{-126} = 2^{-126}\), convert it to scientific notation by formula \(2^x = 10^{x\cdot log_{10} 2}\), \(2^{-126} = 10^{{-126}\cdot log_{10}2}\), \(2^{-126} = 10^{-37.928}\), \(2^{-126} = 1.17549435 \times 10^{-38}\) is minimum positive normalized float value. Remember this is still positive, here minimum does not mean negative value.
There is another thing i.e. how to deal with very small floating point values which are suddenly rounded to zero. These numbers are called subnormal numbers whose exponents is all zeros 0000_0000. For this IEEE 754 single precision format changes to \(0.mantissa \times 2^{-126}\). So smallest possible subnormal number that can be represent in IEEE 754 format have sign bit 0, exponent = 0000_0000, mantissa = 0.00000000000000000000001. Putting in formula we get \(0.00000000000000000000001 \times 2^{-126}\) = \((\frac{1}{2^{23}}) \times (2^{-126})\) = \((2^{-149})\) = \(10^{-149\cdot\log_{10} 2}\) = \(10^{-44.85 }\)= \(1.4 \times 10^{-45}\) .
To increase the range of float there are other data types like double and long double. Double follows the IEEE 754 double precision format which is 64 bit in size so here one sign bit + 11 bit exponent + 52 bit mantissa = 64 bits. Smallest Normalized Value is \(2.22507 \times 10^{-308}\) , largest normalized value is \(1.79769 \times 10^{308}\) , smallest subnormal number is \(4.94 \times 10^{-324}\). Long double data type do not have fixed IEEE 754 standard across all platforms. It varies among 80 bit, 96 bit and 128 bit.
Conclusion
Understanding the internal representation, size variations across architectures, and IEEE 754 standards for floating-point numbers empowers developers to write optimized, portable, and high-performance C programs. Mastering these fundamentals is not just about syntax but about harnessing the full power of the C language for system programming, embedded development, and computational tasks. By choosing the right data type, programmers can maximize efficiency, minimize memory waste, and ensure numerical accuracy—a crucial skill for any C developer.