clay/docs/14_bit_manipulation.md
Claude faea55a9b9
Add comprehensive C learning materials with specialized topic tutorials
Complete learning guide covering ALL C concepts from beginner to advanced:

Main Guide (LEARNING_C_WITH_CLAY.md):
- Added Chapters 3-5: Operators, Control Flow, Loops
- Enhanced Chapters 6-13: Functions, Pointers, Structs, Arrays, Strings,
  Type Casting, Storage Classes, Recursion
- All chapters include extensive Clay library examples
- Progressive difficulty from basics to advanced topics

Specialized Tutorial Files (docs/):
- 14_bit_manipulation.md: Comprehensive bit operations guide
  * Bitwise operators, masks, flags
  * Counting bits, power of 2 operations
  * Practical applications with Clay examples

- 21_standard_library.md: C Standard Library overview
  * stdio.h, stdlib.h, string.h, math.h
  * Clay's zero-dependency approach
  * Custom implementations vs stdlib

- 22_file_io.md: Complete File I/O guide
  * Text and binary file operations
  * Configuration files for Clay apps
  * Error handling and best practices

- 23_command_line_arguments.md: CLI argument parsing
  * argc/argv basics
  * Flag parsing and subcommands
  * Clay application configuration examples

- README_C_TUTORIALS.md: Master index and learning guide
  * Complete chapter overview
  * Learning path recommendations
  * Progress tracking checklist
  * Prerequisites and setup instructions

Features:
- 24 comprehensive chapters covering all C concepts
- 100+ code examples with detailed explanations
- Real-world patterns from Clay library throughout
- Practice exercises for each chapter
- Modular organization for easy navigation
- Zero-dependency programming concepts
- Professional C development practices

Total content: ~70,000+ words of detailed tutorials
2025-11-13 20:32:16 +00:00

662 lines
12 KiB
Markdown

# Chapter 14: Bit Manipulation in C
## Complete Guide with Clay Library Examples
---
## 14.1 Binary Number System
Understanding binary is essential for bit manipulation:
```c
// Decimal vs Binary
0 = 0000
1 = 0001
2 = 0010
3 = 0011
4 = 0100
5 = 0101
6 = 0110
7 = 0111
8 = 1000
```
### Converting Binary to Decimal
```c
#include <stdio.h>
int binaryToDecimal(int binary) {
int decimal = 0, base = 1;
while (binary > 0) {
int lastDigit = binary % 10;
decimal += lastDigit * base;
base *= 2;
binary /= 10;
}
return decimal;
}
int main(void) {
printf("%d\n", binaryToDecimal(1010)); // 10
printf("%d\n", binaryToDecimal(1111)); // 15
return 0;
}
```
---
## 14.2 Bitwise Operators
### AND Operator (&)
```c
// Both bits must be 1
int a = 5; // 0101
int b = 3; // 0011
int c = a & b; // 0001 = 1
// Check if number is even
int isEven(int n) {
return (n & 1) == 0; // Check if last bit is 0
}
```
**Clay Example:**
```c
// Check if corner radius flag is set
typedef enum {
CLAY_CORNER_RADIUS_TOP_LEFT = 1 << 0, // 0001
CLAY_CORNER_RADIUS_TOP_RIGHT = 1 << 1, // 0010
CLAY_CORNER_RADIUS_BOTTOM_LEFT = 1 << 2, // 0100
CLAY_CORNER_RADIUS_BOTTOM_RIGHT = 1 << 3 // 1000
} Clay_CornerRadiusSet;
// Check if top-left corner has radius
if (flags & CLAY_CORNER_RADIUS_TOP_LEFT) {
// Top left corner has radius
}
```
### OR Operator (|)
```c
// At least one bit must be 1
int a = 5; // 0101
int b = 3; // 0011
int c = a | b; // 0111 = 7
// Set specific bit
int setBit(int num, int pos) {
return num | (1 << pos);
}
```
**Clay Example:**
```c
// Combine multiple corner radius flags
int flags = CLAY_CORNER_RADIUS_TOP_LEFT |
CLAY_CORNER_RADIUS_TOP_RIGHT; // 0011 = both top corners
// Add another flag
flags |= CLAY_CORNER_RADIUS_BOTTOM_LEFT; // Now 0111 = three corners
```
### XOR Operator (^)
```c
// Bits must be different
int a = 5; // 0101
int b = 3; // 0011
int c = a ^ b; // 0110 = 6
// Swap two numbers without temp variable
void swap(int *a, int *b) {
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
```
### NOT Operator (~)
```c
// Inverts all bits
int a = 5; // 00000101
int b = ~a; // 11111010 (in 8-bit)
// Clear specific bit
int clearBit(int num, int pos) {
return num & ~(1 << pos);
}
```
### Left Shift (<<)
```c
// Multiply by 2^n
int a = 5; // 0101
int b = a << 1; // 1010 = 10 (multiply by 2)
int c = a << 2; // 10100 = 20 (multiply by 4)
// Fast power of 2
int powerOf2(int n) {
return 1 << n; // 2^n
}
```
**Clay Example:**
```c
// Define bit flags with left shift
typedef enum {
CLAY_CORNER_RADIUS_TOP_LEFT = 1 << 0, // 1
CLAY_CORNER_RADIUS_TOP_RIGHT = 1 << 1, // 2
CLAY_CORNER_RADIUS_BOTTOM_LEFT = 1 << 2, // 4
CLAY_CORNER_RADIUS_BOTTOM_RIGHT = 1 << 3 // 8
} Clay_CornerRadiusSet;
```
### Right Shift (>>)
```c
// Divide by 2^n
int a = 20; // 10100
int b = a >> 1; // 01010 = 10 (divide by 2)
int c = a >> 2; // 00101 = 5 (divide by 4)
// Extract specific bits
int getBits(int num, int start, int count) {
return (num >> start) & ((1 << count) - 1);
}
```
---
## 14.3 Common Bit Operations
### Check if Bit is Set
```c
int isBitSet(int num, int pos) {
return (num & (1 << pos)) != 0;
}
int main(void) {
int num = 5; // 0101
printf("%d\n", isBitSet(num, 0)); // 1 (bit 0 is set)
printf("%d\n", isBitSet(num, 1)); // 0 (bit 1 is not set)
printf("%d\n", isBitSet(num, 2)); // 1 (bit 2 is set)
return 0;
}
```
### Set a Bit
```c
int setBit(int num, int pos) {
return num | (1 << pos);
}
int main(void) {
int num = 5; // 0101
num = setBit(num, 1); // 0111 = 7
printf("%d\n", num);
return 0;
}
```
### Clear a Bit
```c
int clearBit(int num, int pos) {
return num & ~(1 << pos);
}
int main(void) {
int num = 7; // 0111
num = clearBit(num, 1); // 0101 = 5
printf("%d\n", num);
return 0;
}
```
### Toggle a Bit
```c
int toggleBit(int num, int pos) {
return num ^ (1 << pos);
}
int main(void) {
int num = 5; // 0101
num = toggleBit(num, 1); // 0111 = 7
num = toggleBit(num, 1); // 0101 = 5 (back to original)
printf("%d\n", num);
return 0;
}
```
---
## 14.4 Bit Masks
Masks select specific bits:
```c
// Extract RGB components from 32-bit color
typedef struct {
uint32_t color; // 0xAARRGGBB
} Color;
uint8_t getRed(Color c) {
return (c.color >> 16) & 0xFF; // Mask: 0x00FF0000
}
uint8_t getGreen(Color c) {
return (c.color >> 8) & 0xFF; // Mask: 0x0000FF00
}
uint8_t getBlue(Color c) {
return c.color & 0xFF; // Mask: 0x000000FF
}
uint8_t getAlpha(Color c) {
return (c.color >> 24) & 0xFF; // Mask: 0xFF000000
}
uint32_t makeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
return ((uint32_t)a << 24) |
((uint32_t)r << 16) |
((uint32_t)g << 8) |
(uint32_t)b;
}
```
**Clay Example (conceptual):**
```c
// Clay uses float colors, but shows similar concepts
typedef struct {
float r, g, b, a;
} Clay_Color;
// If Clay used packed colors:
uint32_t packColor(Clay_Color c) {
uint8_t r = (uint8_t)(c.r * 255);
uint8_t g = (uint8_t)(c.g * 255);
uint8_t b = (uint8_t)(c.b * 255);
uint8_t a = (uint8_t)(c.a * 255);
return (a << 24) | (r << 16) | (g << 8) | b;
}
```
---
## 14.5 Bit Fields in Structs
Pack multiple values efficiently:
```c
struct Flags {
unsigned int isVisible : 1; // 1 bit
unsigned int isEnabled : 1; // 1 bit
unsigned int priority : 3; // 3 bits (0-7)
unsigned int id : 11; // 11 bits
}; // Total: 16 bits = 2 bytes
int main(void) {
struct Flags f = {0};
f.isVisible = 1;
f.isEnabled = 1;
f.priority = 5;
f.id = 1024;
printf("Size: %zu bytes\n", sizeof(f)); // 2 or 4 (compiler dependent)
printf("Priority: %u\n", f.priority);
return 0;
}
```
**Clay Example (conceptual):**
```c
// Clay could use bit fields for layout flags
typedef struct {
uint32_t layoutDirection : 1; // 0 = horizontal, 1 = vertical
uint32_t wrapChildren : 1; // Wrap to next line
uint32_t alignmentX : 2; // 0-3 for alignment options
uint32_t alignmentY : 2;
uint32_t reserved : 26; // Future use
} Clay_LayoutFlags;
```
---
## 14.6 Counting Set Bits
### Method 1: Loop
```c
int countSetBits(int n) {
int count = 0;
while (n > 0) {
count += n & 1; // Add last bit
n >>= 1; // Shift right
}
return count;
}
```
### Method 2: Brian Kernighan's Algorithm
```c
int countSetBits(int n) {
int count = 0;
while (n > 0) {
n &= (n - 1); // Clear rightmost set bit
count++;
}
return count;
}
// Example: n = 12 (1100)
// 1100 & 1011 = 1000 (count = 1)
// 1000 & 0111 = 0000 (count = 2)
```
### Method 3: Lookup Table
```c
// Precomputed table for 4-bit numbers
int table[16] = {
0, 1, 1, 2, 1, 2, 2, 3,
1, 2, 2, 3, 2, 3, 3, 4
};
int countSetBits(int n) {
int count = 0;
while (n > 0) {
count += table[n & 0xF]; // Count 4 bits at a time
n >>= 4;
}
return count;
}
```
---
## 14.7 Power of Two
### Check if Power of 2
```c
int isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
// Examples:
// 4 (100) & 3 (011) = 0 → true
// 5 (101) & 4 (100) = 4 → false
// 8 (1000) & 7 (0111) = 0 → true
```
### Next Power of 2
```c
int nextPowerOfTwo(int n) {
if (n <= 0) return 1;
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n + 1;
}
int main(void) {
printf("%d\n", nextPowerOfTwo(5)); // 8
printf("%d\n", nextPowerOfTwo(17)); // 32
return 0;
}
```
---
## 14.8 Swap Values
### Without Temporary Variable
```c
void swap(int *a, int *b) {
if (a != b) { // Must check for same address
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
}
```
### Swap Nibbles (4-bit)
```c
int swapNibbles(int n) {
return ((n & 0x0F) << 4) | ((n & 0xF0) >> 4);
}
// Example: 0x5A → 0xA5
```
---
## 14.9 Reverse Bits
```c
uint32_t reverseBits(uint32_t n) {
uint32_t result = 0;
for (int i = 0; i < 32; i++) {
result <<= 1; // Shift result left
result |= (n & 1); // Add rightmost bit of n
n >>= 1; // Shift n right
}
return result;
}
```
---
## 14.10 Parity
Check if number of set bits is even or odd:
```c
int getParity(int n) {
int parity = 0;
while (n > 0) {
parity ^= (n & 1);
n >>= 1;
}
return parity; // 0 = even, 1 = odd
}
```
---
## 14.11 Gray Code
Convert between binary and Gray code:
```c
// Binary to Gray
int binaryToGray(int n) {
return n ^ (n >> 1);
}
// Gray to Binary
int grayToBinary(int n) {
int binary = 0;
while (n > 0) {
binary ^= n;
n >>= 1;
}
return binary;
}
```
---
## 14.12 Position of Rightmost Set Bit
```c
int rightmostSetBit(int n) {
return n & ~(n - 1);
}
// Example: 12 (1100)
// Returns: 4 (0100) - position of rightmost 1
```
---
## 14.13 Toggle All Bits After Rightmost Set Bit
```c
int toggleAfterRightmost(int n) {
return n ^ (n - 1);
}
// Example: 12 (1100)
// Returns: 15 (1111)
```
---
## 14.14 Extract and Set Bit Ranges
```c
// Extract bits from position p to p+n
int extractBits(int num, int p, int n) {
return (num >> p) & ((1 << n) - 1);
}
// Set bits from position p to p+n
int setBits(int num, int p, int n, int value) {
int mask = ((1 << n) - 1) << p;
return (num & ~mask) | ((value << p) & mask);
}
```
---
## 14.15 Practical Applications in Clay
### Bit Flags for UI State
```c
typedef enum {
CLAY_ELEMENT_VISIBLE = 1 << 0, // 0x01
CLAY_ELEMENT_ENABLED = 1 << 1, // 0x02
CLAY_ELEMENT_FOCUSED = 1 << 2, // 0x04
CLAY_ELEMENT_HOVERED = 1 << 3, // 0x08
CLAY_ELEMENT_PRESSED = 1 << 4, // 0x10
CLAY_ELEMENT_SELECTED = 1 << 5, // 0x20
CLAY_ELEMENT_DISABLED = 1 << 6, // 0x40
CLAY_ELEMENT_HIDDEN = 1 << 7 // 0x80
} Clay_ElementFlags;
typedef struct {
uint32_t flags;
} Clay_Element;
// Check state
int isVisible(Clay_Element *el) {
return (el->flags & CLAY_ELEMENT_VISIBLE) != 0;
}
// Set state
void setVisible(Clay_Element *el, int visible) {
if (visible) {
el->flags |= CLAY_ELEMENT_VISIBLE; // Set bit
} else {
el->flags &= ~CLAY_ELEMENT_VISIBLE; // Clear bit
}
}
// Toggle state
void toggleVisible(Clay_Element *el) {
el->flags ^= CLAY_ELEMENT_VISIBLE;
}
// Multiple states at once
void setInteractive(Clay_Element *el) {
el->flags |= (CLAY_ELEMENT_VISIBLE |
CLAY_ELEMENT_ENABLED);
}
```
### Optimized Hash Functions
```c
// Clay uses hashing for element lookup
uint32_t hashString(const char *str, size_t length) {
uint32_t hash = 0;
for (size_t i = 0; i < length; i++) {
hash = (hash << 5) - hash + str[i]; // hash * 31 + c
// Using bit shift instead of multiply
}
return hash;
}
```
### Memory Alignment
```c
// Align size to power of 2
size_t alignSize(size_t size, size_t alignment) {
return (size + alignment - 1) & ~(alignment - 1);
}
// Example: align to 16 bytes
// size = 25
// (25 + 15) & ~15 = 40 & 0xFFFFFFF0 = 32
```
---
## 14.16 Performance Tips
**Use bit operations for:**
- ✅ Powers of 2 multiplication/division
- ✅ Flag checks (faster than booleans)
- ✅ Color packing/unpacking
- ✅ Hash functions
- ✅ Alignment calculations
**Avoid for:**
- ❌ Regular arithmetic (compiler optimizes)
- ❌ Readability-critical code
- ❌ Floating-point operations
---
## 14.17 Key Concepts Learned
- ✅ Bitwise operators: &, |, ^, ~, <<, >>
- ✅ Bit manipulation: set, clear, toggle, check
- ✅ Bit masks and extraction
- ✅ Bit fields in structs
- ✅ Counting set bits
- ✅ Power of 2 operations
- ✅ Practical applications in Clay
- ✅ Performance considerations
---
## Practice Exercises
1. Write a function to count trailing zeros in a number
2. Implement bitwise rotation (rotate left/right)
3. Find the only non-duplicate number in an array (all others appear twice)
4. Swap all odd and even bits in a number
5. Add two numbers without using + operator
6. Implement a bit vector data structure
7. Create a compact permission system using bit flags
8. Write efficient popcount for 64-bit numbers