Rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::env; // (1) Imports `env` module; compile-time resolves to
use std::fs::{File, OpenOptions};
use std::io::{BufReader, BufWriter, Read, Write};
const BUF_SIZE: usize = 4096; // (2) `usize` platform-dependent integer; 32/64-bit.
// Compiler replaces `BUF_SIZE` with literal
// `4096` at compile time. No runtime lookup.
fn caesar_cipher_file(input_path: &str, // (3) `&str` - immutable reference to UTF-8 str
output_path: &str, // slice; pointer and length in registers/stack.
shift: u32) -> std::io::Result<()> {
// Open input file with buffered reader
let input_file = File::open(input_path)?; // (4) `File::open` - OS syscall to open file at
// `input_path`. Returns `Result`; on Err,
// propagates error via `?` (early return).
let mut reader = BufReader::new(input_file); // (5) `BufReader` wraps `File`; heap allocation
// for internal buffer (`BUF_SIZE` default).
// Reduces syscalls; amortized read cost.
// Open output file with buffered writer (truncate existing or create new)
let output_file = OpenOptions::new() // (6) `OpenOptions::new()` - Builder pattern; stack-
.write(true) // allocates `OpenOptions` struct. Method chaining
.create(true) // modifies flags within the struct in-place.
.truncate(true) // Compile-time flag setting for syscall behavior.
.open(output_path)?; // (7) `.open()` - Performs OS file open syscall with
// options set in builder. May create, truncate
// depending on flags. Result propagation on error.
let mut writer = BufWriter::new(output_file); // (8) `BufWriter` wraps `File`; heap allocation
// for write buffer. Buffers output in user-
// space; less frequent/larger write syscalls.
let mut buffer = [0u8; BUF_SIZE]; // (9) `[0u8; BUF_SIZE]` - Stack-allocates byte array
// of 4096 elements. Zero-initialized at function
// entry; fast stack pointer adjustment.
loop { // (10) `loop` - Infinite loop construct. Compiler
// may optimize as tail recursion (or direct
// jump back) if conditions are met.
// Read chunk from input file
let bytes_read = reader.read(&mut buffer)?; // (11) `reader.read` - Calls `read` syscall
// under the hood (via buffered reading).
// Kernel reads file into `buffer` memory.
// Returns `Result<usize>` bytes read count.
if bytes_read == 0 { // (12) `bytes_read == 0` - Integer comparison. Checks
break; // End of file // if EOF reached (syscall returned 0 bytes).
// Conditional branch instruction.
}
// Process each byte in the chunk
for byte in &mut buffer[..bytes_read] { // (13) `for...in` - Iterator loop over byte slice.
// `&mut buffer[..bytes_read]` - mutable slice
// view into stack array up to `bytes_read`.
*byte = ((u32::from(*byte) + shift) % 256) as u8; // (14) `u32::from(*byte)` - Zero-extends `u8`
// to `u32`. Prevents overflow during add.
// Integer promotion handled by compiler.
// (15) `+ shift` - 32-bit integer addition. ALU
// operation. `shift` loaded from stack/reg.
// (16) `% 256` - Modulo 256 operation; reduces
// result to `u8` range. Compiler may
// optimize using bitwise AND (`& 0xFF`).
// (17) `as u8` - Type cast; truncates `u32` to `u8`.
// Implicitly happens during assignment back
// to `*byte` which is `&mut u8`.
} // (18) Loop iteration end; next byte processing.
// Write processed chunk to output file
writer.write_all(&buffer[..bytes_read])?; // (19) `writer.write_all` - Uses buffered writer;
// may buffer in user space. Flushes to OS
// `write` syscall less frequently (if full).
} // (20) Outer loop continues reading/processing file chunks.
// Ensure all data is flushed to disk
writer.flush()?; // (21) `writer.flush` - Forces buffered data to OS
// `write` syscall. Ensures data persisted to file.
// Important before function exit for data integrity.
Ok(()) // (22) `Ok(())` - Returns successful `Result`; unit
// type `()` signals no value returned on success.
// Informs caller operation completed successfully.
}
fn main() {
let args: Vec<String> = env::args().collect(); // (23) `env::args()` - OS syscall (via Rust stdlib)
// to fetch command line arguments as strings.
// Allocates `Vec<String>` on heap to store them.
if args.len() != 4 { // (24) `args.len() != 4` - Checks argument count.
eprintln!("Usage: {} <input> <output> <shift>", args[0]); // (25) `eprintln!` - Writes formatted string
// to standard error stream (unbuffered).
std::process::exit(1); // (26) `std::process::exit(1)` - Terminates process
// immediately with exit code 1 (error status).
}
// Parse shift value
let shift = match args[3].parse::<u32>() { // (27) `args[3].parse::<u32>()` - Parses 4th arg
// string into `u32`. May allocate/dealloc for
// parsing. Returns `Result<u32, ParseIntError>`.
Ok(n) => n, // (28) `Ok(n) => n` - On successful parse, extracts
// `u32` value `n` from `Ok` variant.
Err(_) => { // (29) `Err(_)` - Matches any `Err` variant from parse.
eprintln!("Error: Shift must be a positive integer");
std::process::exit(1); // (30) Exit on parse error; invalid shift input.
}
}; // (31) Match arm end for shift parsing.
// Process files
match caesar_cipher_file(&args[1], &args[2], shift) { // (32) Calls `caesar_cipher_file` function.
Ok(_) => println!("File processed successfully"), // (33) On `Ok` from function, prints success
// message to standard output (buffered).
Err(e) => { // (34) On `Err` from function call (I/O error).
eprintln!("Error processing files: {}", e); // (35) Prints error message to stderr with error
// details `e` (dynamic dispatch for display).
std::process::exit(1); // (36) Exits process with error status (1) if
// `caesar_cipher_file` encountered an error.
} // (37) Match arm for `caesar_cipher_file` result ends.
} // (38) Main function `match` expression ends.
} // (39) `main` function end. Program execution ends after `main`.
C Implementation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// C implementation will be added here
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#define BUF_SIZE 4096
BOOL cci_f(LPCSTR fIn, LPCSTR fOut, DWORD shift) {
HANDLE hIn = INVALID_HANDLE_VALUE, hOut = INVALID_HANDLE_VALUE;
unsigned char aBuffer[BUF_SIZE];
unsigned char ccBuffer[BUF_SIZE];
DWORD nIn = 0, nOut = 0, iCopy = 0;
BOOL WriteOK = FALSE;
if (GetFileAttributesA(fIn) == INVALID_FILE_ATTRIBUTES) {
printf("Input file does not exist\n");
return FALSE;
}
hIn = CreateFileA(fIn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hIn == INVALID_HANDLE_VALUE) {
printf("Cannot open input file\n");
return FALSE;
}
hOut = CreateFileA(fOut, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hOut == INVALID_HANDLE_VALUE) {
CloseHandle(hIn);
printf("Cannot create output file\n");
return FALSE;
}
while (ReadFile(hIn, aBuffer, BUF_SIZE, &nIn, NULL) && nIn > 0) {
// (1) `ReadFile`: Invokes OS kernel syscall; context switch
// required. User mode to kernel mode transition incurs
// CPU cycle overhead. File descriptor `hIn` looked up in
// process file table by kernel to locate file object.
// (2) `aBuffer`: Memory block likely stack-allocated (scope-
// dependent). Address passed by pointer to `ReadFile`
// for direct write by kernel. Kernel directly populates
// this region; bypasses user-space buffer copies.
// (3) `BUF_SIZE`: Constant; compile-time known value.
// Instructs `ReadFile` max bytes to fetch. Larger size
// potentially fewer syscalls, but larger kernel buffer
// usage. OS may limit max read size internally.
// (4) `&nIn`: Pointer to stack `DWORD` (`int`); output
// parameter for bytes actually read by kernel. Kernel
// writes directly to this memory location after `ReadFile`
// completes, modifying the user space variable.
// (5) `NULL`: Overlapped I/O structure; NULL = synchronous.
// Thread blocks in kernel-mode sleep state during read
// operation; CPU relinquishes time slice. Wake-up
// interrupt upon I/O completion resumes thread.
// (6) `&&`: Short-circuit logical AND. Right operand (`nIn > 0`)
// evaluation only proceeds if `ReadFile` returns TRUE (non-
// zero). Prevents dereferencing uninitialized `nIn`
// if `ReadFile` fails (returns FALSE, e.g., EOF).
// (7) `nIn > 0`: Integer comparison instruction (e.g., `cmp` x86).
// CPU flags updated based on result. Branch prediction
// unit guesses loop continuation or exit. Mispredict
// penalty delays execution pipeline.
for (iCopy = 0; iCopy < nIn; iCopy++) {
// (8) `for` loop: Counter-controlled iteration. `iCopy` is
// likely register-allocated (if optimized). Increments
// and bounds check ( `< nIn`) performed per loop cycle.
// Instruction pipelining overlaps loop iterations.
// (9) `aBuffer[iCopy]`: Array access; pointer arithmetic.
// Calculates memory address: base address (`aBuffer`) +
// (index `iCopy` * element size). Fetches `BYTE` value
// from RAM. Cache hit improves access latency.
// (10) `+ shift`: Integer addition operation. `shift` likely
// loaded from register or immediate. ALU (Arithmetic
// Logic Unit) performs the addition in CPU. Result in reg.
// (11) `% 256`: Modulo operation, effectively bitwise AND
// with `0xFF` for `BYTE` range. Ensures wrap-around
// within 0-255. ALU division or bitwise AND instruction
// sequence. Optimizers might prefer bitwise AND.
// (12) `(BYTE)`: Explicit type cast; informs compiler to treat
// result as unsigned 8-bit integer. Truncates any
// higher-order bits if the result exceeds 255.
// May be implicitly handled by assignment to `ccBuffer`.
ccBuffer[iCopy] = (BYTE)((aBuffer[iCopy] + shift) % 256);
// (13) `ccBuffer[iCopy] = ...`: Assignment. Value from RHS
// (result of calculation) copied to memory location of
// `ccBuffer` at index `iCopy`. Cache write operation.
// Subsequent reads may experience cache hit or miss.
} // (14) Loop closing brace; compiler generates jump instruction
// back to loop top if loop condition is still met. Branch
// prediction affects performance if condition outcome varies.
if (!WriteFile(hOut, ccBuffer, nIn, &nOut, NULL) || nOut != nIn) {
// (15) `WriteFile`: Kernel system call to write to file
// `hOut`. Similar kernel transition overhead as
// `ReadFile`. Data transfer from user space `ccBuffer`
// to kernel buffers, then to disk or output stream.
// (16) `ccBuffer`: Data source for `WriteFile`. Memory block
// containing modified bytes ready to be written.
// Contents copied to kernel space. Potential for double-
// buffering within OS for asynchronous disk operations.
// (17) `nIn`: Bytes to write, obtained from previous `ReadFile`.
// Kernel enforces write count constraint. Short writes
// possible due to disk space or errors; check `nOut`.
// (18) `&nOut`: Output param for actual bytes written. Kernel
// writes result into `nOut` in user space after write
// syscall completes. Crucial to compare `nOut` against
// `nIn` for write success validation.
// (19) `||`: Logical OR, short-circuiting. If `WriteFile`
// fails (returns FALSE) OR if written bytes count
// `nOut` doesn't match expected `nIn`, then the 'if'
// block is executed. Error check logic.
// (20) `nOut != nIn`: Integer comparison. Validates successful
// write of all intended bytes. Mismatch suggests I/O error.
// Kernel/filesystem may report errors if write failed.
printf("Write error occurred\n");
// (21) `printf`: Standard C library function call. Potentially
// involves buffering in user-space `stdio` library.
// Ultimately a syscall (like `write` or OS specific) to
// write string "Write error..." to standard output stream.
break;
// (22) `break`: Control flow statement; jump out of innermost
// `while` loop. Compiler generates machine code to skip
// to instruction after the `while` loop's closing brace.
// Loop termination due to write error.
} // (23) `if` block end; no special internal implications. Scope
// delimitation for conditional execution.
WriteOK = TRUE;
// (24) `WriteOK = TRUE`: Boolean assignment. Sets flag indicating
// successful write (at least for *this* loop iteration).
// Value `TRUE` (likely 1 or non-zero int) stored in `WriteOK`
// variable's memory location (stack or global/static).
} // (25) Outer `while` loop closing brace. Jump back to `ReadFile`
// call at the beginning if the `while` condition (result of
// `ReadFile` and `nIn > 0`) is still true. Loop repeats.s
FlushFileBuffers(hOut);
CloseHandle(hIn);
CloseHandle(hOut);
return WriteOK;
}
int main(int argc, char* argv[]) {
if (argc != 4) {
printf("Usage: %s <input> <output> <shift>\n", argv[0]);
return 1;
}
DWORD shift = (DWORD)atoi(argv[3]);
if (!cci_f(argv[1], argv[2], shift)) {
printf("Operation failed\n");
return 1;
}
printf("File processed successfully\n");
return 0;
}
Exercise
Let us implement this in C++23 or C++20