Data Storage in Memory (C Language)
Data Storage in Memory (C Language)
Basic Built-in Types:
char: 1 byteshort: 2 bytesint: 4 byteslong: 4/8 bytes (system - dependent)long long: 8 bytesfloat: 4 bytesdouble: 8 bytes
Type Fmailies:
Integer Family:
-
char -
unsigned char,signed char
(Note:charstores ASCII values, so it belongs to the integer family.) -
short -
unsigned short,signed short -
int -
unsigned int,signed int -
long -
unsigned long,signed long
Floating - Point Family:
floatdouble
Constructed (User - Defined) Types:
- Arrays:
int arr[10]→ Type:int[10] - Structs:
struct - Enums:
enum - Unions:
union
Pointer Types, Void Type (Briefly Mentioned)
Data Storage in Memory
Integers:
Integers have three binary representations: sign - magnitude (original code), one's complement, and two's complement.
For positive integers, all three codes are identical. We focus on negative numbers:
Example:
int num = -10;
// Sign - magnitude: 10000000000000000000000000001010
// One's complement: 11111111111111111111111111110101 (flip bits except sign)
// Two's complement: 11111111111111111111111111110110 (one's complement + 1)
Computers store integers using two's complement! (Critical!)
An int uses 32 bits. In hex, -10 is 0xfffffff6. On a little - endian machine, bytes are stored in reverse: f6 ff ff ff.
Endianness:
Assume lower addresses are on the left, higher on the right. Storing 0x11223344:
- Big - endian: Bytes are
11 22 33 44(high byte at low address). - Little - endian: Bytes are
44 33 22 11(low byte at low address).
Definition:
- Little - endian: Least significant byte (LSB) at the lowest address.
- Big - endian: Most significant byte (MSB) at the lowest address.
Detecting Endianness (Code Example):
int checkEndian() {
int val = 1; // Binary: 00000000 00000000 00000000 00000001
return *(char*)&val; // Check the first byte
}
int main() {
int result = checkEndian();
if (result == 1) {
printf("Little - endian\n");
} else {
printf("Big - endian\n");
}
return 0;
}
Explanation:
For val = 1 (hex 0x00000001):
- Little - endian: First byte is
01(LSB), so*(char*)&valis1. - Big - endian: First byte is
00(MSB), so*(char*)&valis0.
Integer Range & Promotion:
Take signed char and unsigned char as examples:
Binary values: 00000000 (0) → 01111111 (127) → 10000000 (-128) → 11111111 (-1).
Integer Promotion:
- For
signedtypes: Extend with the sign bit (0 for positive, 1 for negative).
E.g.,signed char(8 bits) →int(32 bits):0b11111111(char) becomes0b11111111111111111111111111111111(int). - For
unsignedtypes: Extend with 0s.
Sign - Magnitude ↔ Two's Complement:
-
Sign - Magnitude → Two's Complement:
- Keep the sign bit, flip all other bits (one's complement).
- Add 1 to the one's complement (two's complement).
-
Two's Complement → Sign - Magnitude:
Either:- Subtract 1, then flip all bits (excluding sign).
- Or: Flip all bits, then add 1.
Floating - Point Numbers:
A floating - point number V is represented as:
V = (-1)^S × M × 2^E
Example: 5.5_{10} = 101.1_2 = (-1)^0 × 1.011 × 2^2
IEEE 754 Standard:
- 32 - bit (float): 1 sign bit (S), 8 exponent bits (E), 23 mantissa bits (M).
- 64 - bit (double): 1 sign bit (S), 11 exponent bits (E), 52 mantissa bits (M).
Mantissa (M) Handling:
Since 1 ≤ M < 2, M is stored as 1.xxxxxx (binary). The leading 1 is omitted to save space (e.g., 1.01 → store 01).
Exponent (E) Handling:
Eis stored with a bias: Add 127 (for 8 - bit E) or 1023 (for 11 - bit E) to the actual exponent.- Example: For
2^10, E is stored as10 + 127 = 137(binary10001001).
Special Cases for E:
-
E = 0 (all bits 0):
- Exponent is
1 - bias(e.g.,1 - 127 = -126for 8 - bit E). - Mantissa
Mis0.xxxxxx(no leading 1). - Used for ±0 or very small numbers.
- Exponent is
-
E = 1 (all bits 1):
- If
M = 0: Represents ±infinity (sign determined by S).
- If
Code Verification (Floating - Point vs Integer):
#include <stdio.h>
int main() {
int val = 9;
float* floatPtr = (float*)&val;
printf("Value of val: %d\n", val); // Output: 9
printf("Value of *floatPtr: %f\n", *floatPtr); // Output: 0.000000
*floatPtr = 9.0;
printf("Value of val: %d\n", val); // Output: 1091567616
printf("Value of *floatPtr: %f\n", *floatPtr); // Output: 9.000000
return 0;
}
Explanation:
-
Storing
9(int:00000000 00000000 00000000 00001001) as a float:- S = 0, E = 0 (all bits 0), M =
000000000000000000001001. - Exponent:
1 - 127 = -126, Mantissa:0.00000000000000000001001. - Result:
(-1)^0 × 0.00000000000000000001001 × 2^-126(extremely small, prints as 0.000000).
- S = 0, E = 0 (all bits 0), M =
-
Storing
9.0(float):9.0 = 1001.0_2 = 1.001 × 2^3.- S = 0, E = 3 + 127 = 130 (binary
10000010), M =00100000000000000000000. - Binary representation:
01000001000100000000000000000000(hex0x41200000→ decimal1091567616).