cis5480-25sp (Spring 2025) Home Schedule Assignments Tools & Refs Code Style Guidelines

Operating Systems Design and Implementation (Spring 2025)

Overview

Below are some of the general style qualities we expect your programs to have to receive full credit under the style criteria. Unfortunately, this is not an exhaustive list as there are a myriad ways to write ugly code. Please refer to each assignment spec for other style practices to follow if written.

In most professional work environments, if not all, you are expected to follow that company’s style standards and ways of writing documentation. Learning to follow a style guide, and writing code with a group of other developers where the style is consistent among them, are valuable job skills. This becomes increasingly more evident as the number of people who see your code increases and during the Penn Operating System final project.

Disclaimer

Goals

Contents

General Guidelines

Overall, your code should:

  1. Be readable: Other programmers should easily understand your logic.
    • Just because you can read it, does not mean it is written well.
  2. Be modular: Break tasks into small, reusable functions.
    • Avoid writing all your code within the entry point of a C program, the main function.
    • Your main function should not contain all of your program’s functionality.
    • Break down your code into modular functions with purposeful meaning.
  3. Avoid redundancy: Write helper functions for repeated code.
    • If your code is identical in several places, this means it is best to write a helper function for that.
  4. Follow consistent styling conventions: Formatting, naming, and layout.
  5. Do not leave dead code, uncommented code, and non-descriptive comments throughout your files.
    • If you find debugging statements to be imperative, use preprocessing directives to “activate” debugging.
    • Leaving printf calls in a program is also violating style, as it allows for ambiguity in the output of a program.
    • Make sure your comments are descriptive when necessary; Do not write them in second person.
    • Remove all Todos throughout source and header files.
  6. Make sure to error check all necessary functions. These will be indicated via an \* in the assignment spec.
    • No error checking will result in points deducted.

Whitespace and Indentation

Bad Example:

if (a == b) { foo(); }

Good Example:

if (a == b) {
    foo();
}

Bad Example:

#define long_string "The operating system is like the final layer in an onion. Except, when you hit the soil the onion is in. Then that's a problem for the Electrical Engineering Department."

Good Example:

#define long_string "The operating system is like the final layer in an onion. \
                    Except, when you hit the soil the onion is in. Then that's \
                    a problem for the Electrical Engineering Department."

Naming and Variables

Avoid Global Variables: Pass values through parameters or return them.

Bad Example:

int count;  // Global variable!

int incrementCount(){
    return count++;
}

Good Example:

int incrementCount(int count) {
    return count + 1;
}

int main(){
    int count = 0;
    count = incrementCount(count);
}

Bad Example:

int variedForLoop(int param_one, uint32_t param_two, size_t param_three){
    uint8_t flag = 0;
    for(long i = param_one; i < param_two; i += param_three){
        if(i == param_two){
            flag = true;
        }
        if(flag) break;
    }
    return (int)flag;
}

Good Example:

bool variedForLoop(int loop_start, int loop_end, int step_size){
    for(int i = loop_start; i < loop_end; i += step_size){
        if(i == param_two){
            return true;
        }
    }
    return false;
}

Core C Statements

Bad Example:

if (x >= 80) { ... }
if (x >= 60 && x < 80) { ... }

Good Example:

if (x >= 80) {
    ...
} else if (x >= 60) {
    ...
}

Bad Example:

if (x == 0){
    if(y ==1){
        if(z == 0){
            foo();
            return;
        }
        buzz();
        return;
    }
    buzz();
    return;
}
buzz();
return;

Good Example:

if (x == 0 && y ==1 && z == 0){
    foo();
    return;
} 
buzz();
return;

Redundancy

Bad Example:

if (x < y) {
    foo();
    printf("Hi");
} else {
    printf("Hi");
}

Good Example:

if (x < y) {
    foo();
}
printf("Hi");

Efficiency

Bad Example:

for (int i = 0; i < strlen(str); i++) { ... }

Good Example:

int len = strlen(str);
for (int i = 0; i < len; i++) { ... }

Bad Example:

typedef struct _point{
    int x;
    int y;
} Point;

void init_point(Point* ptr) {
  *ptr = (Point) {
     .x = 0,
     .y = 0,
  };
}

int main() {
  Point* p = malloc(sizeof(Point));
  init_point(p);

  printf("%d\n", p->x);
  free(p);
}

Good Example:

typedef struct _point{
    int x;
    int y;
} Point;

void get_point(point* ptr) {
  *ptr = (point) {
     .x = 0,
     .y = 0,
  };
}

int main() {
  point p;
  get_point(&p);

  printf("%d\n", p.x);
}

Bad Example:

int main() {
  char* str = strdup("hello"); // assume STR must be on the heap for some reason.

  // Capitalize the string;
  char* cap = strdup(str);
  for (size_t i = 0; i < strlen(str); i++) {
    cap[i] = toupper(str[i]);
  }
  free(str);
  str = cap;
}

Good Example:

int main() {
  char* str = strdup("hello"); // assume STR must be on the heap for some reason.

  // Capitalize the string in-place
  size_t len = strlen(str);
  for (size_t i = 0; i < len; i++) {
    str[i] = toupper(str[i]);
  }
}

Comments

Comments should:

  1. Describe intent rather than obvious mechanics.
    • Line by line comments are not necessary.
  2. Be placed at the file, function, block, or line level.
  3. Not be written in the second person unless absolutely necessary.
    • Comments written in the second person are suspicious, as AI programs typically leave comments in this way.
    • (e.g. “Or whatever signals you may need”, “Follows your guideline for X”, etc.)
  4. Do not leave commented out code.

1. File Header

Describe the file’s purpose, author, and any relevant details.

Example:

/* CS5480 Assignment 0
 * Author: Jane Doe
 * Purpose: Implements a dynamic array in C.
 */

2. Function Header

Explain inputs, outputs, assumptions, and any edge cases. These should be written within the .h file with implementation specific comments in the .c

Example:

/* Function: incrementCount
 * ------------------------
 * Increments the given counter by 1.
 * 
 * count: Current count value.
 * 
 * Returns: Incremented count.
 */
int incrementCount(int count);

3. Block Comments

Provide insight into logical flow or significant chunks of code.

Example:

// Loop through the array to find the maximum value.
for (int i = 0; i < len; i++) {
    ...
}
// Reap all terminated child processes until there are none left.
// Do not block if none ready to be reaped.
while(waitpid(-1, NULL, WNOHANG)){
}

4. Line Comments

Explain dense or complex operations. Of course, do not write these if the code you write is self descriptive enough.

Example of redundant comment:

out = malloc(sizeof(buff)); // Allocate sizeof(buff) bytes 

Example of good comment:

out = malloc(sizeof(header) + sizeof(point) * 2); // Allocating memory for a 'pair' of points with a header at the start.

Example of Bad Leftover Comments:

// TODO: Implement me!
int main(int argc, char *argv[]){
    pid_t child = fork(); //ok don't forget to check if it's 0

    if(child == 0){
      //ok now we're in the kid.
      printf("Let's check if we get here correctly. Here is the pid %d.\n", child); 
      //omg you totally forgot this will just print 0. 

      char *child_argv[] = {"sleep", "10", NULL};
      execvp(child_argv[0], child_argv);
      // we should not reach here but let's check 

      // printf("text here"); // ugh they don't want us to use printf. ok 
      const char *error_str = "error indicator\n";
      write(STDERR_FILENO, error_str, strlen(error_str) + 1); //need to write to stand erro bc idk ????
      exit(EXIT_FAILURE);
    }

    //wait what do we even do here??
    waitpid(-1, NULL, 0); // Do we need flags?
    // waitpid(child, NULL, WUNTRACED);
    // waitpid(child, NULL, WNOHANG | WUNTRACED); 
    // waitpid(child, NULL, WNOHANG | WUNTRACED | WCONTINUED);  i know it's one of these.
    return;

    sigsuspend(0); //?
}

Yes, we do see submissions like this. Please remove all comments that are not required, print statement, and dead code.

Functions and Procedural Design

Bad Example:

void max(int a, int b, int *result) {
    *result = (a > b) ? a : b;
}

Good Example:

int max(int a, int b) {
    return (a > b) ? a : b;
}

Bad Example:

void signal_sigint(int signal){
  //signal stuff
}

void signal_specific_installer_SIGINT() {
  struct sigaction sa = {0};
  sa.sa_flags = SA_RESTART;
  sa.sa_handler = signal_sigint;
  sigaction(SIGINT, &sa, NULL);
  return;
}

Good Example:


void signal_sigint(int signal) {
    // Handle SIGINT signal
}

void install_handler(int signal, int flags, sigset_t blocked_on_entry, 
                     void (*handler)(int), struct sigaction *previous) {
    struct sigaction sig_act_struct = {
        .sa_flags = flags,
        .sa_handler = handler,
        .sa_mask = blocked_on_entry
    };

    sigaction(signal, &sig_act_struct, previous);
}

Tools for Code Style and Memory Safety

Run these tools regularly during development:

make format
make tidy-check
valgrind ./your_program

Submission Guidelines

Attribution

This document is inspired by the style guidelines provided in many of the CS classes at Stanford University. Adapted for this course by Travis McGaha and Joel Ramirez.