{"id":16382733,"url":"https://github.com/baderouaich/the-zero-overhead-principle","last_synced_at":"2026-02-25T21:03:13.701Z","repository":{"id":182842284,"uuid":"622354855","full_name":"baderouaich/the-zero-overhead-principle","owner":"baderouaich","description":"Little demonstration of the Zero Overhead principle.","archived":false,"fork":false,"pushed_at":"2025-03-03T23:26:39.000Z","size":33,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-02T17:56:01.410Z","etag":null,"topics":["c","cplusplus","cpp","the-zero-overhead-principle","zero-overhead","zero-overhead-abstraction","zero-overhead-principle"],"latest_commit_sha":null,"homepage":"","language":"Assembly","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/baderouaich.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-04-01T21:29:22.000Z","updated_at":"2024-10-29T16:14:43.000Z","dependencies_parsed_at":"2025-04-17T10:39:19.985Z","dependency_job_id":"370f9933-7669-4f8b-8d43-63212b984a0b","html_url":"https://github.com/baderouaich/the-zero-overhead-principle","commit_stats":null,"previous_names":["baderouaich/the-zero-overhead-principle"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/baderouaich/the-zero-overhead-principle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baderouaich%2Fthe-zero-overhead-principle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baderouaich%2Fthe-zero-overhead-principle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baderouaich%2Fthe-zero-overhead-principle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baderouaich%2Fthe-zero-overhead-principle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/baderouaich","download_url":"https://codeload.github.com/baderouaich/the-zero-overhead-principle/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baderouaich%2Fthe-zero-overhead-principle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29839944,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-25T20:42:33.054Z","status":"ssl_error","status_checked_at":"2026-02-25T20:42:21.322Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","cplusplus","cpp","the-zero-overhead-principle","zero-overhead","zero-overhead-abstraction","zero-overhead-principle"],"created_at":"2024-10-11T04:06:12.630Z","updated_at":"2026-02-25T21:03:13.686Z","avatar_url":"https://github.com/baderouaich.png","language":"Assembly","funding_links":[],"categories":[],"sub_categories":[],"readme":"## What is the zero overhead principle ?\n\n\u003e \"If you have an abstraction, it should not cost anything compared to writing the equivalent code at a lower level. So, if I have a matrix multiplier, it should be written in such a way that you could not drop to C level of abstraction and use arrays and pointers and such and run faster.\"\n\u003e [Bjarne Stroustrup from the Lex Fridman podcast](https://youtu.be/uTxRF5ag27A?t=2655)\n\n\nThe zero-overhead principle is a C++ design principle that states:\n- You don't pay for what you don't use.\n- What you do use is just as efficient as what you could reasonably write by hand.\n\nIn general, this means that no feature should be added to C++ that would impose any overhead, whether in time or space, greater than a programmer would introduce without using the feature.\nThe only two features in the language that do not follow the zero-overhead principle are runtime type identification and exceptions, and are why most compilers include a switch to turn them off.\n[cppreference](https://en.cppreference.com/w/cpp/language/Zero-overhead_principle)\n\n\u003cimg src=\"https://github.com/user-attachments/assets/554f7aa8-b1ea-4dfe-ae61-2316223e1333\" width=\"500\"/\u003e\n\n## Demonstration\nThis project includes a demonstration that contrasts equivalent code written in C and C++. Both versions are compiled to assembly language, allowing for a direct comparison of the generated instructions.\n\n## Objective\nTo illustrate the Zero Overhead Principle, the C++ code should generate assembly instructions that are fewer than or equal to those produced by the C code.\n\nThis is our C code: \n```C\ntypedef struct Player {\n    int x;\n    int y;\n} Player;\n\nstatic void player_setX(Player *p, int x) { p-\u003ex = x; }\nstatic int player_getX(Player *p) { return p-\u003ex; }\nstatic void player_setY(Player *p, int y) { p-\u003ey = y; }\nstatic int player_getY(Player *p) { return p-\u003ey; }\nstatic void player_move_left(Player *p, int amount) { p-\u003ex -= amount; }\nstatic void player_move_right(Player *p, int amount) { p-\u003ex += amount; }\nstatic void player_move_up(Player *p, int amount) { p-\u003ey -= amount; }\nstatic void player_move_down(Player *p, int amount) { p-\u003ey += amount; }\n\nint main(void) {\n    Player p1 = {55, 47}, p2 = {9, 74}, p3 = {10, 25};\n    player_move_right(\u0026p2, 5);\n    player_move_down(\u0026p3, 5);\n    player_setX(\u0026p1, player_getX(\u0026p2) * player_getX(\u0026p3));\n    player_setY(\u0026p1, player_getY(\u0026p2) / player_getY(\u0026p3));\n    player_move_left(\u0026p1, player_getX(\u0026p2) / 2);\n    player_move_up(\u0026p1, player_getY(\u0026p2) / 2);\n    player_setX(\u0026p1, player_getX(\u0026p1) + 1);\n    player_setX(\u0026p2, player_getX(\u0026p2) + 2);\n    player_setX(\u0026p3, player_getX(\u0026p3) + 3);\n    return player_getX(\u0026p1) * player_getX(\u0026p2) * player_getX(\u0026p3);\n}\n```\n\nHere’s a comparable implementation using C++ features such as classes, templates, and operator overloading:\n```C++\ntemplate \u003ctypename T\u003e\nclass Entity {\nprotected:\n    T x{};\n    T y{};\n\npublic:\n    Entity(T x, T y) : x(x), y(y) {}\n    virtual ~Entity() = default;\n\n    void setX(T x) noexcept { this-\u003ex = x; }\n    T getX() const noexcept { return x; }\n    void setY(T y) noexcept { this-\u003ey = y; }\n    T getY() const noexcept { return y; }\n\n    virtual void move_left(T amount) = 0;\n    virtual void move_right(T amount) = 0;\n    virtual void move_up(T amount) = 0;\n    virtual void move_down(T amount) = 0;\n    virtual Entity\u0026 operator+=(T amount) = 0;\n};\n\nclass Player : public Entity\u003cint\u003e {\npublic:\n    Player(int x, int y) noexcept : Entity(x, y) {}\n\n    void move_left(int amount) override { this-\u003ex -= amount; }\n    void move_right(int amount) override { this-\u003ex += amount; }\n    void move_up(int amount) override { this-\u003ey -= amount; }\n    void move_down(int amount) override { this-\u003ey += amount; }\n\n    Player\u0026 operator+=(int amount) override {\n        this-\u003ex += amount;\n        this-\u003ey += amount;\n        return *this;\n    }\n};\n\nint main() {\n    Player p1(55, 47), p2(9, 74), p3(10, 25);\n    p2.move_right(5);\n    p3.move_down(5);\n    p1.setX(p2.getX() * p3.getX());\n    p1.setY(p2.getY() * p3.getY());\n    p1.move_left(p2.getX() / 2);\n    p1.move_up(p2.getY() / 2);\n    p1 += 1;\n    p2 += 2;\n    p3 += 3;\n    return p1.getX() * p2.getX() * p3.getX();\n}\n```\n\u003e Note: The use of interfaces and pure virtual functions here serves to demonstrate the capabilities of C++ and is not strictly necessary for this particular example. The goal is to showcase how C++ can use features not available in C while still adhering to the Zero Overhead Principle.\n\nC++ compiled assembly code\n```shell\nclang++ -S program.cpp -o program.asm --std=c++20 -Os -Wall -Wextra -Wpedantic\n```\n```asm\nmain:                                 \n\tmovl\t$27872, %eax               \n\tretq\n```\n\u003e The C++ compiler has optimized away our Player class and the abstractions we had, all methods were inlined and\n\u003e everything was narrowed down and calculated by the compiler at compile time to the `movl $27872` instruction which is the result value that was returned by the main function.\n\nC compiled assembly code\n```shell\nclang -S program.c -o program.asm --std=c17 -Os -Wall -Wextra -Wpedantic\n```\n```asm\nmain:\n\tmovl\t$27872, %eax \n\tretq\n```\n\u003e We can see that the C compiler optimized our program by inlining function calls and objects construction to end up with the final value calculated at compile time.\n\n## Analysis\nBoth the C and C++ compilers performed optimizations such as inlining function calls and calculating values at compile time. Remarkably, despite the additional features employed in C++, the final assembly code generated was equivalent to that of the C code, demonstrating the Zero Overhead Principle in action.\n\n## Conclusion\nThis demonstration illustrates that the C++ and C compilers achieved similar optimizations, such as inlining and compile-time calculations. By utilizing templates and object-oriented programming (OOP) in C++, we can write abstractions without sacrificing performance. This empowers developers to leverage advanced features like classes, methods, and templates while still achieving the efficiency of C-level code and sometimes even [better](https://youtu.be/uTxRF5ag27A?t=2678), of course if we respect the [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines).\n\n## References\n- [Bjarne Stroustrup explaining the zero overhead principle](https://www.youtube.com/watch?v=G5zCGY0tkq8)\n- [C++ guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines)\n\n### Corrections\nIf you think there is a mistake, misconception or misinformation, feel free to open an issue at the [issue tracker][tracker].\n\n[tracker]: https://github.com/baderouaich//the-zero-overhead-principle/issues\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaderouaich%2Fthe-zero-overhead-principle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbaderouaich%2Fthe-zero-overhead-principle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaderouaich%2Fthe-zero-overhead-principle/lists"}