Code Style Guide¶
This guide defines the coding standards for the EmbSec Kit project. Consistent code style improves readability, maintainability, and collaboration.
General Principles¶
- Clarity over cleverness: Write code that is easy to understand
- Consistency: Follow existing patterns in the codebase
- Documentation: Comment complex logic and document public APIs
- Testing: Write tests for new functionality
- Security: Consider security implications of all code changes
C Code Style¶
We use LLVM style with some modifications as defined in .clang-format:
Formatting Rules¶
- Indentation: 4 spaces (no tabs)
- Line length: 80 characters maximum
- Braces: Linux kernel style (opening brace on same line for functions)
- Pointer alignment: Right-aligned (
char *str, notchar* str)
Automatic Formatting¶
Use clang-format to automatically format your code:
# Format a single file
clang-format -i src/myfile.c
# Format all C files
find . -name "*.c" -o -name "*.h" | xargs clang-format -i
Naming Conventions¶
Functions¶
// Public API functions: embsec_module_action()
void embsec_uart_init(void);
int embsec_gpio_read(uint8_t pin);
// Internal functions: module_action()
static void uart_configure_baudrate(uint32_t baud);
static int gpio_validate_pin(uint8_t pin);
Variables¶
// Local variables: snake_case
int byte_count = 0;
char *user_input = NULL;
// Global variables: g_snake_case
volatile uint32_t g_system_ticks = 0;
static char g_buffer[256];
// Constants: UPPER_SNAKE_CASE
#define MAX_BUFFER_SIZE 1024
#define UART_BAUDRATE 115200
Types¶
// Structs: snake_case with _t suffix
typedef struct {
uint32_t address;
size_t size;
} memory_region_t;
// Enums: snake_case with _e suffix
typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT,
GPIO_MODE_ALTERNATE
} gpio_mode_e;
Code Organization¶
File Structure¶
/*
* filename.c - Brief description
*
* Detailed description of the file's purpose
*
* Author: Name <email>
* SPDX-License-Identifier: MIT
*/
// 1. System includes
#include <stdint.h>
#include <string.h>
// 2. Project includes
#include "embsec/embsec.h"
#include "embsec/uart.h"
// 3. Local includes
#include "internal.h"
// 4. Macros and constants
#define BUFFER_SIZE 256
// 5. Type definitions
typedef struct {
// ...
} local_state_t;
// 6. Static variables
static local_state_t g_state;
// 7. Static function declarations
static void helper_function(void);
// 8. Public function implementations
void embsec_public_function(void)
{
// Implementation
}
// 9. Static function implementations
static void helper_function(void)
{
// Implementation
}
Documentation¶
Function Documentation¶
/**
* @brief Initialize the UART peripheral
*
* @param baud Baud rate (e.g., 115200)
* @param config Configuration flags
*
* @return 0 on success, negative error code on failure
*
* @note This function must be called before any other UART operations
*/
int embsec_uart_init(uint32_t baud, uint32_t config);
Inline Comments¶
// Single-line comments for simple explanations
x = (y + 1) * 2; // Account for header byte
/*
* Multi-line comments for complex explanations
* that require more detail or context
*/
if (complex_condition) {
// Explain why this is necessary
perform_special_operation();
}
Python Code Style¶
For Python code (tests, scripts), follow PEP 8:
Key Rules¶
- Indentation: 4 spaces
- Line length: 79 characters (72 for docstrings)
- Naming: snake_case for functions/variables, PascalCase for classes
- Imports: Group and sort imports (standard, third-party, local)
Example¶
#!/usr/bin/env python3
"""
Module docstring describing the purpose.
"""
import os
import sys
from typing import List, Optional
import pytest
from serial import Serial
from embsec_test import TestFramework
class LabTest:
"""Test class for lab exercises."""
def __init__(self, port: str) -> None:
"""Initialize test with serial port."""
self.port = port
self.serial: Optional[Serial] = None
def run_exploit(self, payload: bytes) -> bool:
"""
Run exploit with given payload.
Args:
payload: Exploit payload bytes
Returns:
True if exploit succeeded
"""
# Implementation
pass
CMake Style¶
Formatting¶
- Use lowercase for commands:
add_library(), notADD_LIBRARY() - Indent with 2 spaces
- One argument per line for multi-argument commands
Example¶
# Define library
add_library(embsec-sdk STATIC
src/uart.c
src/gpio.c
src/timer.c
)
# Set properties
target_include_directories(embsec-sdk
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# Conditional logic
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
Shell Scripts¶
Style Rules¶
- Use
#!/usr/bin/env bashshebang - Set safety flags:
set -euo pipefail - Use
"${variable}"for variable expansion - Check command existence before use
- Provide help text with
-h/--help
Example¶
#!/usr/bin/env bash
#
# Script description
#
set -euo pipefail
# Constants
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly DEFAULT_BUILD_DIR="build"
# Functions
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
Options:
-b, --build-dir DIR Build directory (default: ${DEFAULT_BUILD_DIR})
-v, --verbose Enable verbose output
-h, --help Show this help message
EOF
}
# Main
main() {
local build_dir="${DEFAULT_BUILD_DIR}"
local verbose=0
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-b|--build-dir)
build_dir="$2"
shift 2
;;
-v|--verbose)
verbose=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Error: Unknown option: $1" >&2
usage
exit 1
;;
esac
done
# Implementation
}
main "$@"
Git Commit Messages¶
Format¶
type(scope): brief description
Longer explanation of the change, why it was needed,
and any important implementation details.
Fixes: #123
Types¶
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringtest: Test additions or changesbuild: Build system changesci: CI/CD configuration changeschore: Other maintenance tasks
Examples¶
feat(sdk): add SPI peripheral support
Implement SPI driver with support for master mode operation.
Includes DMA support for efficient data transfers.
- Add embsec_spi_init() and configuration functions
- Implement interrupt-driven and DMA transfer modes
- Add comprehensive test coverage
Fixes: #45
Code Review Checklist¶
Before submitting a merge request, ensure:
- Code follows the style guide
- All tests pass (
make test) - New code has appropriate tests
- Documentation is updated
- No compiler warnings
- Performance impact evaluated
- Backwards compatibility maintained
Tools and Automation¶
Pre-commit Hooks¶
Install pre-commit hooks to automatically check style:
# Install pre-commit
pip install pre-commit
# Install hooks
pre-commit install
# Run manually
pre-commit run --all-files
Editor Configuration¶
VS Code¶
{
"C_Cpp.clang_format_style": "file",
"editor.formatOnSave": true,
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true
}
Vim¶
" Use clang-format
autocmd FileType c,cpp nnoremap <buffer> <leader>f :!clang-format -i %<CR>
" Basic settings
set expandtab
set shiftwidth=4
set softtabstop=4
Questions?¶
If you have questions about code style:
- Check existing code for examples
- Refer to the
.clang-formatconfiguration - Ask in your merge request for clarification