1---2name: c-conventions3description: C coding conventions and best practices for C17 development. Use when writing, reviewing, or refactoring C code to ensure security, const-correctness, platform portability, and consistent parameter and naming conventions.4---56# C Coding Conventions78## General Principles910- Follow C17 standard for broad compiler compatibility (including MSVC)11- Write self-documenting code with clear naming and structure12- Apply const-correctness throughout the codebase13- Use defensive programming with parameter validation14- Keep functions focused and modular15- Ensure platform portability (Linux, macOS, Windows)16- Prefer security over convenience in API design17- Write code that compiles with strict warnings enabled1819## C Standard and Compatibility2021- Use **C17 standard** exclusively for maximum compiler compatibility22- Avoid C23-specific features (not yet supported by MSVC)23- Do not use C++ code or C++-specific features24- Avoid platform-specific system calls when possible25- Test on all target platforms regularly (Linux, macOS, Windows)26- Use standard C library functions only27- Handle platform differences through preprocessor directives when necessary2829## Const Correctness3031- All input parameters should be `const` when not modified32- Apply `const` to pointer targets, not just pointers: `const char*` not `char* const`33- Use `const` to document intent and prevent accidental modification34- Examples:35 - ✅ Correct: `KString KStringCreate(const char* pStr, const size_t Size);`36 - ✅ Correct: `int KStringCompare(const KString a, const KString b);`37 - ❌ Incorrect: `KString KStringCreate(char* pStr, size_t Size);`3839## Comparison Conventions4041- **Always place constants on the left side of comparisons** (constant-left style)42- This prevents accidental assignment when `=` is used instead of `==`43- Examples:44 - ✅ Correct: `if (NULL == ptr)`, `if (0 == value)`, `if (true == condition)`45 - ❌ Incorrect: `if (ptr == NULL)`, `if (value == 0)`, `if (condition == true)`46- Apply to all comparisons including pointer checks, numeric values, and booleans47- Benefits: Compiler error if `=` is mistakenly used instead of `==`4849## Parameter Naming Conventions5051- **`Size`**: Count of bytes (for byte array parameters)52- **`cchSize`**: Count of characters (for character array parameters when distinct from bytes)53- **Pointer parameters**: PascalCase with `p` prefix (e.g., `pStr`, `pData`, `pBuffer`)54- **Value parameters**: PascalCase (e.g., `Encoding`, `Length`, `Index`)55- Use descriptive names that indicate purpose and units56- Be explicit about what size represents (bytes vs characters vs elements)5758## Secure API Design5960- **Require explicit length parameters** for all functions accepting `char*` pointers61- Never rely on null-terminated strings alone (avoid `strlen()` in library code)62- Provide explicit size to prevent buffer overflows63- Validate all size parameters before use64- Check for arithmetic overflow in size calculations65- Use `size_t` for all size-related parameters and return values6667## Function Naming6869- Use prefix for all public API functions (e.g., `KString` prefix)70- Use PascalCase for public functions: `KStringCreate`, `KStringCompare`71- Use prefix + underscore for private functions: `KS_ValidatePointer`, `KS_Release`72- Action verbs should be clear and descriptive73- Common patterns:74 - Create/Destroy for resource management75 - Get/Set for property access76 - Convert for type transformations77 - Validate for checks7879## Variable Naming8081- **Local variables**: PascalCase (e.g., `MyVariable`, `StringLength`, `BufferSize`)82- **Function parameters**: PascalCase (e.g., `InputString`, `MaxLength`)83- **Pointer variables**: PascalCase with `p` prefix (e.g., `pData`, `pBuffer`, `pString`)84- **Type names**: PascalCase (e.g., `KString`, `KStringEncoding`)85- **Enum constants**: UPPER_SNAKE_CASE with prefix (e.g., `KSTRING_ENCODING_UTF8`)86- **Macro definitions**: UPPER_SNAKE_CASE with prefix (e.g., `KSTRING_MAX_SHORT_LENGTH`)87- **Static functions**: Prefix with project abbreviation (e.g., `KS_` for KString internals)8889## Type Definitions9091- Use `typedef` for struct types to avoid `struct` keyword in declarations92- Opaque types: Only define typedef in header, full struct in implementation93- Use descriptive type names in PascalCase94- Define enums with explicit values when they represent protocol/format specifications9596## Enums9798- Use explicit values for enums that map to external specifications99- Prefix enum constants with type name in UPPER_SNAKE_CASE100- Add comments for each enum value explaining its purpose101- Use `typedef enum` to avoid `enum` keyword in declarations102- Example:103 ```c104 typedef enum {105 KSTRING_ENCODING_UTF8 = 0, // Default UTF-8 encoding106 KSTRING_ENCODING_UTF16LE = 1, // UTF-16 Little Endian107 KSTRING_ENCODING_UTF16BE = 2, // UTF-16 Big Endian108 KSTRING_ENCODING_ANSI = 3 // ANSI/Windows-1252 (legacy)109 } KStringEncoding;110 ```111112## Memory Management113114- Use `calloc()` for all dynamic allocations (zero-initialization)115- Never use `malloc()` - always prefer `calloc()` for safety116- Check all allocation results for NULL before use117- Document ownership transfer clearly in function comments118- Functions that return pointers transfer ownership (caller must free)119- Functions that take `const` pointers do not take ownership120- Provide cleanup functions for resource types (e.g., `KStringDestroy`)121122## Error Handling123124- Return error indicators that can't be confused with valid values125- Use sentinel values for errors (e.g., `UINT32_MAX` for invalid size)126- Document error conditions clearly in function comments127- Use defensive programming: validate all parameters128- Check for NULL pointers before dereferencing129- Check for arithmetic overflow before operations130- No exceptions - use return values for error reporting131132## Function Structure133134- Keep functions short and focused on single responsibility135- Use early returns to reduce nesting depth136- Validate parameters at function start137- Group related operations logically138139## Header Organization140141- Include guards using `#ifndef`/`#define`/`#endif`142- Order: includes, macros, types, function declarations143- Example:144 ```c145 #ifndef KSTRING_H146 #define KSTRING_H147148 #include <stddef.h>149 #include <stdint.h>150 #include <stdbool.h>151152 // Macros and constants153 #define KSTRING_MAX_SHORT_LENGTH 12154155 // Type definitions156 typedef struct KString KString;157 typedef enum { /* ... */ } KStringEncoding;158159 // Public API declarations160 KString KStringCreate(const char* pStr, const size_t Size);161 void KStringDestroy(const KString kstr);162163 #endif // KSTRING_H164 ```165166## Implementation File Organization167168- Order: includes, private macros, private types, private functions, public functions169- Group related functions together170- Use static inline for performance-critical helpers171172## Comments173174- Use `//` for all comments (single-line and multi-line)175- Comment the "why" not the "what"176- Document complex algorithms and optimizations177- Add comments for bit manipulation and non-obvious logic178- Keep comments concise and focused179- Update comments when code changes180181## Code Formatting182183- Use `.clang-format` configuration for automatic formatting184- Indentation: 4 spaces (no tabs)185- Braces: Opening brace on next line for functions and blocks186- Line length: Keep under 120 characters when practical187- Align related declarations for readability188189## Bit Manipulation190191- Use descriptive macro names for bit masks and shifts192- Document bit field layouts clearly193- Use helper functions for extracting/combining bit fields194- Use `static_assert` to verify size assumptions at compile time195196## Platform Portability197198- Use standard types from `<stdint.h>`: `uint32_t`, `uint64_t`, `size_t`199- Use `<stdbool.h>` for bool type instead of custom definitions200- Handle endianness differences when needed201- Use preprocessor for platform-specific code202- Test on Linux, macOS, and Windows regularly203- Use CMake for cross-platform build configuration204205## Compiler Warnings206207- Build with strict warnings enabled:208 - GCC/Clang: `-Wall -Wextra -Wpedantic`209 - MSVC: `/W4`210- Treat warnings as errors in development builds211- Fix all warnings - don't suppress them unless absolutely necessary212- Document any warning suppressions with reasoning213214## Static Assertions215216- Use `static_assert` to verify compile-time assumptions217- Check sizes, alignments, and enum value ranges218- Example:219 ```c220 #include <assert.h>221222 // Verify structure size matches specification223 static_assert(sizeof(KString) == 16, "KString must be exactly 16 bytes");224225 // Verify bit field sizes226 static_assert(sizeof(uint32_t) * 8 >= 32, "uint32_t must be at least 32 bits");227 ```228229## Inline Functions230231- Use `static inline` for small, performance-critical helpers232- Define inline functions in implementation file, not header (unless needed by multiple files)233- Keep inline functions simple (1-3 lines typical)234235## Performance Considerations236237- Pass small structs by value (≤16 bytes for register passing)238- Use `const` to enable compiler optimizations239- Avoid unnecessary pointer indirection240- Use inline functions for hot paths241- Consider cache locality in data structure design242- Document performance-critical sections243244## Testing Strategy245246- Write test programs in separate `_examples/` directory247- Test all public API functions248- Include edge cases: NULL pointers, zero sizes, maximum sizes249- Test on all target platforms250- Use assertion macros for test validation251- Document expected behavior in test code252253## Documentation254255- Document all public API functions in header file256- Include purpose, parameters, return value, and notes257- Keep documentation concise but complete258- Update documentation when API changes259- **CRITICAL: Always verify documentation against actual implementation**260261## Code Review Checklist262263- [ ] All public functions have documentation comments264- [ ] Const correctness applied throughout265- [ ] Constant-left comparisons used consistently266- [ ] All size parameters use `size_t` type267- [ ] NULL pointer checks before all pointer dereferences268- [ ] Arithmetic overflow checks for size calculations269- [ ] Memory allocated with `calloc()`, checked for NULL270- [ ] All allocations have corresponding cleanup path271- [ ] Code compiles without warnings on all platforms272- [ ] Static assertions verify compile-time assumptions273- [ ] Function names follow naming conventions274- [ ] Comments explain "why" not "what"275- [ ] Code formatted according to `.clang-format`276277## Build System (CMake)278279- Use CMake 3.30+ for modern features280- Support multiple platforms (Linux, macOS, Windows)281- Generate both shared and static libraries282- Use Ninja generator for fast parallel builds283- Separate examples into `_examples/` subdirectory284- Build artifacts in `_build/` directory (gitignored)