Skip to content

maihd/maicstyle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MaiHD's C/C++ programming style

Notes

  • I'm still learning and practicing for better as C/C++. Ideas and opinions may wrong.
  • Mai English is not good, if You find the typos, wrong words and wrong meanings, please help!
  • Some Mai projects will follow its own style (but not too different from this style) for special reasons. Ex: vectormath
  • I use other projects style guide for thoses projects. It help me learn the others, and new stuffs, why not?
  • Because I will use Zig and Beef for some future projects, each languages has its own styles, I will follow the style, but the heart of priciple will be same: Simply make the job done!
  • Based on the important of the section, I will bring it first the most important, last section is the least important.
  • Note: this project can be consider as a R&D for Mai personal work, you can find some ideas in docs folder.

Language can affect this style

Language that mostly can use DoD approachs:

  • C/C++
  • Beef
  • Zig
  • C#

Table of Contents

  1. Inventing on Principles
  2. Workflow
  3. Programming Languages, Standards, Spirits
  4. Naming convention
  5. Naming convention 2
  6. Naming cheatsheet
  7. Types
  8. Scoping
  9. File layout
  10. Project architecture
  11. Build system
  12. Tooling
  13. License
  14. Additional Resources

Inventing on Principles

  • Do what matter to get the job done!
  • Immediate feedback
  • What you see is what you get: WYSIWYG
  • Simple, open, immediate, low level, debug/discipline
    • The new SOLID principles
    • Keep it simple and small, for product
    • Keep it slow and steady, for development product
    • Open mind to the problem
    • Open data for the program to do what it needs to do
    • Open source for people
    • Open the black box practice
    • Immediate feedback, also know as low-latency iterations
    • Inventing on principles (recursive until there are no principles needed)
    • Incrementally development
    • Low level for abstractions
    • Love and passion
    • Learn the hard way
    • Debug easily, focus on development, and use better tools
    • Discipline, donot break the rules of the project (each project have each own rules)
    • All principles support each others
  • Self-reliance, mindfulness
    • "What I cannot create, I cannot understand" - Richard Feynman
    • First, use it; second, attempt to create it with simple implementation; third, use it better
    • Stay focused on the project, and the project only, right now!
  • Zen creating & living!

Workflow

Working on it.

Programming Languages, Standards, Spirits

  • Basically use C99 and C++11.
    • Update 5/6/2024: C11 (C17 just a fix bugs version of C11) and C++17 widely support now (MSCV, Clang, GCC). But without appreciate reasons, you should avoid thoses features.
    • Update 3/7/2025: C11 and C++20
  • Follow spririts of C, simple and easy to read.
  • #pragma once is widely supported now. Use it preferly to header guards.
  • Use unix encoding.
  • Content file only support ASCII. Donot use utf8 file format.
  • Prefer code that both compile on C and C++, especially on header files.
  • Some features can be support both on C and C++ with extensions, define a keyword with preprocessor.
  • Preprocessor is not bad. Duck typing is not bad. Un-tested code is bad. Write the code are needed to be written, test and proof that code work, are the good resolutions for thoses problems.
  • Prefer clang (and family like zig cc) for toolchains, feel free to use extensions if project is clang-only.
  • Deep dive in ProgLang.md

Naming convention

Please know that naming convention in C/C++ is not forcing in variant type of projects. Mean that naming for readable more important than conventions.

  • Typename: PascalCase. Ex: Texture, Shader, Image, ...
  • Function name: PascalCase, ModuleName_FunctionName. Ex: ArrayPush, Texture_New, ...
  • Enums, constants: ALL_CAPS_CASE. Ex: PI, NULL, PIXEL_RGBA, ...
  • Enums only: TypeName_MemberName. Ex: JsonError_OutOfMemory, FileAccess_ReadWrite, ...
  • Variables, fields, paramaters: camelCase. Ex: texture.width, texture.height, ...
  • Custom keywords: __snake_case. Ex: __enum_type, __default_init, __defer, __typename, __scope, ...
  • Reuse keywords instead of define new: constexpr, __forceinline, alignas, alignof, offsetof, container_of, __vectorcall, ...

Naming convention 2

This convention is more common in C/C++. So I accept this.

  • Typename: PascalCase. Ex: Texture, Shader, Image, ...
  • Module name: snake_case. Ex: vec2, mat4, ...
  • Function name: snake_case, module_name_function_name. Ex: array_push, texture_new, ...
  • Enums, constants: ALL_CAPS_CASE. Ex: PI, NULL, PIXEL_RGBA, ...
  • Enums only: TypeName_MemberName. Ex: JsonError_OutOfMemory, FileAccess_ReadWrite, ...
  • Variables, fields, paramaters: snake_case. Ex: texture.width, texture.height, ...
  • Custom keywords: __snake_case. Ex: __enum_type, __default_init, __defer, __typename, __scope, ...
  • Reuse keywords instead of define new: constexpr, __forceinline, alignas, alignof, offsetof, container_of, __vectorcall, ...

Naming cheatsheet

This section need a database, because naming is enormous and must have only one meaning.

  • Init/Deinit: for initialization/deinitialization, no return pointer
  • Create/Destroy: create new memory, init/deinit, and return pointer (object)
  • Alloc/Free: actually request memory from system
  • Acquire/Release: get memory (also resources) from a buffer/arena/allocator (not return to system when call release)

Types

  • Integer type: use specified width integers for data structures, int for parameters, return types, local variables.

    • int8_t/uint8_t instead of char/unsigned char in data structures.
    • int16_t/uint16_t instead of short/unsigned short in data structures.
    • int32_t/uint32_t instead of int/unsigned int in data structures.
    • int64_t/uint64_t instead of long long/unsigned long long (long is 32-bit on Windows) in data structures.
    • In some cases, there will need float32_t/float64_t instead of float/double
    • Specified width integers in ensure the data structures are same size independent on platforms.
    • int and familiar is prefer because this help compiler do optimization. (rarely use, only helpful for uncommon platforms)
  • float prefer to double, only use double when needed.

  • (C only) Generic types: Array(T), Buffer(T), HashTable(T). Avoid T* for multiple values. Should add prefix T.

  • T* mean pass-by-reference, it mustnot be NULL.

  • Use value semantic, pass-by-value. For performance reason, make sure use const to prevent evil work on data structures.

  • Typedef struct, enum, union. Prefer explicit aligned data structures.

    typedef struct ALIGNAS(vec3, 16) // ALIGNAS is crossplatform of __declspec(align)
    {
        float x, y, z;
    } vec3;
    
    typedef enum WindowFlags
    {
        ...
    } WindowFlags;
    
    typedef union Handle
    {
        void*       onWindows;
        uint64_t    onUnix;
    } Handle;
  • Plain-old data prefer to C++ struct.

  • Avoid use C++ namespace, because C doesnot support. So avoid enum class too.

  • Extended primitive types: vectors and matrices (for graphics and game programming)

    • vec2, vec3, vec4: single precision floating-point vectors (32-bit per component)
    • ivec2, ivec3, ivec4: signed integer vectors (32-bit per component)
    • uvec2, uvec4, uvec4: unsigned interger vectors (32-bit per component)
    • mat2, mat3, mat4: single precision floating-point matrices (32-bit per component)
    • imat2, imat3, imat4: signed integer vectors (32-bit per component)
    • umat2, umat3, umat4: unsigned integer vectors (32-bit per component)
    • bool2, bool3, bool4: one-byte wide component (1-bit per component)
    • <std_wided_prim>x<components>_t (uint32x4_t, int32x4_t, float32x4_t, ...): SIMD primitive types

Scoping

  • Single { } in one line, add newline after it.
  • But all definition of macro when have multiple lines.

File layout

  • File Header (beginning of the file, not to confusing with .h files)

    • Optional meta information, grouping by a block of coments
    • Pragma, header guards, compiler/linker options
    • Include all needed dependencies
    • Declaration of all types
    • Declaration of all functions/macros. But donot declare main.
  • File Body

    • Definitions of all types
    • Definitions of all functions
  • File Footer

    • An optional end-of-file mark. Ex: //! EOF
    • Should end with a newline, some compilers need this (gcc family)
  • Grouping

    • Functions and types declaration should be grouping
    • Functions and types need to align by columm, easy to find return-type, function name
    • Seperate functions, types declaration group with 1 empty line
    • Separate functions, types define with 2 empty lines

Function

  • Grouping chunk by work, what to do
  • Prefer clear, readable code
  • Prefer pure function if available
  • Avoid declare one line variables for pointer type (missing *)
  • Can use 2 newlines to seperating big chunk of code

Project architecture

  • Filename: prefer PascalCase. Maybe have Namespace_ prefix. Ex: Example_HelloWorld.c
  • Libraries/modules should be small. The smallest size of a library is a single header file. The smallest size of a module is a function.
  • Prefer test of module, usage of module. Unit tests should help, but not always.
  • Should have an real-life application come with it.
  • Everything should have been maintaining, so the place of VCS.
  • Self-reliance, so less dependencies. Add and use with care. Even standard library (see examples/free_runtime_1 for more details).

Build system

  • Prefer premake over cmake
  • But knowing cmake can be help
  • Base knowlege of gmake/VisualStudio always needed
  • Some incremental build systems like: ninja, FASTBuild,... Should only use when needed
  • gmake maybe best fit for many projects, counting cross-platforms
  • Sometime build.bat is all I need

Tooling (helpful and need to learn)

  • Clang and LLVM, and families
  • Clang Static Analyzer
  • Clang Format
  • Clang Tidy
  • Clang AST dump (for bindgen and preprocessing)
  • Undefined behavior sanitizer (all compilers)
  • Memory sanitizer (all compilers)
  • Thread sanitizer?
  • Tracy Profiler
  • Platform's native profiler
  • VSCode clangd (LSP for coding C/C++ with VSCode, better than VSCode Intellisense, also support swizzle syntax for vector primitives)
    • Note (11/03/2024): clangd is extremely using too much resources (RAM, CPU) when project have large header files (commonly with single header file libraries)
  • Visual Studio and helpers (not only compiler and code editor part)

License

Why you need a license for coding style. Copyright MaiHD @ Heart and Head.

Additional Resources

This section is a resources to other styles that help me through time, and it's worth to findout. It's also proved production-ready, inuse by many products, companies. (You will find its' gamedev-oriented).

About

Mai C/C++ programming style, C/C++ a combine to form a new language (can be said so)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages