JS
C

JavaScript to C

10 lessons

Progress0%
1Variables & Types2Functions3Arrays & Pointers4Objects → Structs5Memory Management6Preprocessor & Headers7String Handling in Depth8Enums and Bitwise Operations9Bit-Fields and Unions10Multi-File Projects and Linking
All Mirror Courses
JS
C
Enums and Bitwise Operations
MirrorLesson 8 of 10
Lesson 8

Enums and Bitwise Operations

C enums, bitwise operators, and the flags pattern

Introduction

In this lesson, you'll learn about enums and bitwise operations in C. Coming from JavaScript, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.

Mirror Card
JS
From JavaScript:

In JavaScript, you're familiar with c enums, bitwise operators, and the flags pattern.

C
In C:

C has its own approach to c enums, bitwise operators, and the flags pattern, which we'll explore step by step.

The C Way

Let's see how C handles this concept. Here's a typical example:

C
C Example
#include <stdio.h>

// enum — integer constants starting at 0
typedef enum {
    NORTH = 0,
    SOUTH,    // 1
    EAST,     // 2
    WEST      // 3
} Direction;

// Enum with explicit values (flags/bitmask pattern)
typedef enum {
    PERM_NONE    = 0,
    PERM_READ    = 1 << 0,  // 1
    PERM_WRITE   = 1 << 1,  // 2
    PERM_EXECUTE = 1 << 2,  // 4
    PERM_RW      = PERM_READ | PERM_WRITE  // 3
} Permission;

int main(void) {
    Direction dir = NORTH;

    // Bitwise ops
    Permission perm = PERM_READ | PERM_WRITE;  // 3

    // Test a flag
    if (perm & PERM_READ) printf("can read\n");

    // Add a flag
    perm |= PERM_EXECUTE;

    // Remove a flag
    perm &= ~PERM_WRITE;

    // Toggle a flag
    perm ^= PERM_EXECUTE;

    // Shift
    int x = 1 << 4;   // 16 — power of 2
    int y = 64 >> 2;   // 16

    printf("perm=%d\n", perm);
    return 0;
}

Comparing to JavaScript

Here's how you might have written similar code in JavaScript:

JS
JavaScript (What you know)
// Enum-like constants via Object.freeze
const Direction = Object.freeze({
  NORTH: 0, SOUTH: 1, EAST: 2, WEST: 3
});

// Flags via bit values
const Perm = Object.freeze({
  READ:    0b001,  // 1
  WRITE:   0b010,  // 2
  EXECUTE: 0b100,  // 4
});

// Combine flags
let perm = Perm.READ | Perm.WRITE;   // 3

// Test flag
if (perm & Perm.READ) console.log("can read");

// Remove flag
perm &= ~Perm.WRITE;  // 1 (remove write)

// Shift operators
1 << 3;  // 8 (left shift)
16 >> 2; // 4 (right shift)
Mirror Card
JS
From JavaScript:

You may be used to different syntax or behavior.

C
In C:

C enum assigns consecutive integers starting at 0; or explicit values

Mirror Card
JS
From JavaScript:

You may be used to different syntax or behavior.

C
In C:

enum values are just integers — no runtime type checking

Mirror Card
JS
From JavaScript:

You may be used to different syntax or behavior.

C
In C:

typedef enum {} Name; makes Name usable without 'enum' prefix

Mirror Card
JS
From JavaScript:

You may be used to different syntax or behavior.

C
In C:

Bitwise operators: & (AND), | (OR), ^ (XOR), ~ (NOT), << (left shift), >> (right shift)

Mirror Card
JS
From JavaScript:

You may be used to different syntax or behavior.

C
In C:

Flags pattern: use 1 << n for each bit, combine with |, test with &, clear with &= ~flag

Step-by-Step Breakdown

1. Defining Enums

enum creates a named integer type with symbolic constants. typedef makes the name usable without the 'enum' keyword prefix.

JS
JavaScript
const Color = Object.freeze({ RED: 0, GREEN: 1, BLUE: 2 });
C
C
typedef enum { RED, GREEN, BLUE } Color;
Color c = GREEN;  // c == 1

2. Flags Pattern

Use 1 << n for each bit flag so each flag occupies a unique bit. Combine flags with OR, test with AND.

JS
JavaScript
const flags = Perm.READ | Perm.WRITE;
if (flags & Perm.READ) { ... }
C
C
typedef enum {
    FLAG_A = 1 << 0, // 001
    FLAG_B = 1 << 1, // 010
    FLAG_C = 1 << 2  // 100
} Flags;
Flags f = FLAG_A | FLAG_C; // 101
if (f & FLAG_A) { /* set */ }

3. Add, Remove, Toggle Flags

Three essential bit operations for flag manipulation: |= to add, &= ~flag to remove, ^= to toggle.

JS
JavaScript
perm |= Perm.WRITE;       // add
perm &= ~Perm.WRITE;      // remove
perm ^= Perm.WRITE;       // toggle
C
C
perm |= PERM_WRITE;        // set bit
perm &= ~PERM_WRITE;       // clear bit (~inverts all bits)
perm ^= PERM_WRITE;        // toggle bit

4. Shift Operators

Left shift (<<) multiplies by 2^n; right shift (>>) divides by 2^n. Both are O(1) and faster than multiplication for powers of 2.

JS
JavaScript
1 << 3  // 8
256 >> 4 // 16
C
C
int page_size = 1 << 12;  // 4096
int half = value >> 1;     // divide by 2
int byte_idx = bit_pos >> 3; // which byte contains this bit
Common Pitfall
Right-shifting a negative signed integer is implementation-defined in C. Use unsigned types for bit manipulation.

Common Mistakes

When coming from JavaScript, developers often make these mistakes:

  • C enum assigns consecutive integers starting at 0; or explicit values
  • enum values are just integers — no runtime type checking
  • typedef enum {} Name; makes Name usable without 'enum' prefix
Common Pitfall
Don't assume C works exactly like JavaScript. While the concepts may be similar, the syntax and behavior can differ significantly.

Key Takeaways

  • typedef enum { A, B, C } Name; — A=0, B=1, C=2 by default
  • Flags: use 1 << n for each bit; combine with |, test with &, clear with &= ~flag
  • Shift operators: << multiplies by power of 2, >> divides
  • Use unsigned types (unsigned int) for bit manipulation — signed right-shift is implementation-defined
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your JavaScript code in C to practice these concepts.
PreviousNext