{"id":26502892,"url":"https://github.com/grassator/defer-for-c","last_synced_at":"2025-08-23T11:10:24.355Z","repository":{"id":66098730,"uuid":"379767880","full_name":"grassator/defer-for-c","owner":"grassator","description":"Experimental function-level defer for pure C89","archived":false,"fork":false,"pushed_at":"2021-06-24T01:10:13.000Z","size":11,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-04T08:07:32.825Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grassator.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2021-06-24T01:10:09.000Z","updated_at":"2023-06-26T13:13:22.000Z","dependencies_parsed_at":"2023-04-21T10:33:26.857Z","dependency_job_id":null,"html_url":"https://github.com/grassator/defer-for-c","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/grassator/defer-for-c","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grassator%2Fdefer-for-c","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grassator%2Fdefer-for-c/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grassator%2Fdefer-for-c/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grassator%2Fdefer-for-c/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grassator","download_url":"https://codeload.github.com/grassator/defer-for-c/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grassator%2Fdefer-for-c/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267361758,"owners_count":24074983,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-27T02:00:11.917Z","response_time":82,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2025-03-20T18:36:15.973Z","updated_at":"2025-07-27T13:09:10.210Z","avatar_url":"https://github.com/grassator.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# defer-for-c\n\nThis is a small single-header implementation of Go-style `defer`\nstatements allowing to schedule a function call to be run before\nreturning from the functions.\n\n## Quick Start\n\n```c\n#include \u003cstdio.h\u003e\n\n/* Include the library header */\n#include \"defer.h\"\n\nint main(void) {\n  USE_DEFER();\n\n  FILE *f = fopen(__FILE__, \"rb\");\n\n  /* You can use DEFER on any function that accepts a pointer\n   * `fclose` is a common call that can benefit from DEFER */\n  if (f) DEFER(fclose, f);\n\n  return;\n}\n```\n\n## Supported Platforms\n\nThe code is known to work with MSVC on Windows and GCC and Clang on Linux.\nSupports C89/C99/C11/C17 versions of the C language.\n\nFor default implementation `alloca` support is required.\nYou can switch to the manual stack reservation mode that does\nnot required `alloca`(see below).\n\n## Public API\n\n`USE_DEFER();` statement-like macro needs to be included at the top\nof any procedure using `DEFER()` macros.\n\n`DEFER` function-like macro that can be viewed as\na function with the following signature:\n\n```c\ntypedef void(*defer_callback_t)(void *payload);\nvoid DEFER(defer_callback_t callback, void *payload);\n```\n\nThe library also redefines `return` as a macro but the definition\ndoes not have any observable effects on procedures without `USE_DEFER()`.\n\n## Common Issues\n\n### Explicit `return` in `void` Procedures\n\nIf you try to compile a procedure like this:\n\n```c\nvoid foo(void) {\n  USE_DEFER();\n}\n```\n\n\u003e Static error detection only works on MSVC and Clang. If anyone knows how to force GCC\nto error out on a *particular* unused variable help is very much appreciated.\n\nYou will get an error that looks similar to this (depending on the compiler):\n\n```\n'ERROR_void_functions_must_use_an_explicit_return_at_the_end': unreferenced local variable\n```\n\nTo fix it include a `return;` statement at the end of the procedure:\n\n```c\nvoid foo(void) {\n  USE_DEFER();\n  return;  /* \u003c-- fix */\n}\n```\n\n### Missing `USE_DEFER` at the Start of the Procedure\n\nIf you try to compile a file like this:\n```c\nvoid dummy(void) {}\n\nint main() {\n  DEFER(dummy);\n  return 0;\n}\n```\n\nYou will get an error that looks similar to this (depending on the compiler):\n\n```\nlabel 'USE_DEFER_must_appear_at_the_start_of_the_functions_using_DEFER' was undefined\n```\n\nTo fix it include a `USE_DEFER();` statement at the start of the procedure:\n\n```c\nvoid dummy(void) {}\n\nint main() {\n  USE_DEFER(); /* \u003c-- fix */\n  DEFER(dummy);\n  return 0;\n}\n```\n\n### No `alloca` Mode\n\nYou can switch to the manual stack reservation mode by adding\n`#define DEFER_NO_ALLOCA` directive before including the header.\n\nIn this mode you need to provide the number of `DEFER()` slots to reserve\nwhen calling `USE_DEFER(4)`. In this case we are reserving `4` slots.\nThere is a runtime `assert()` for overflows if you have reserved\nless slots than you have `DEFER()` calls.\n\n## How Does It Work?\n\n`USE_DEFER` sets up a list of entries that include the pointer to a\nuser-provided callbacks and payload for each of the `DEFER()` calls.\nDepending on whether `DEFER_NO_ALLOCA` is defined either a linked list\nor a fixed-size array is used on the stack.\n\nThe main trick is the redefinition of `return` keyword as macro such that it\ndoes nothing in regular procedures. For procecures that `USE_DEFER()`\nit goes through the list of pushed callbacks in the reverse order and call.\n\n## Performance\n\nEven though `return` keyword is redefined for all procedures it is optimized\nout even with `-O1` level.\n\nFor procedures that `USE_DEFER` you will have extra stack space allocated\nand there is a loop for each `return` statement that might or might not be\ncoalesced into a single one by the compiler since they are all identical.\n\nUsual overhead of calling-through-a-pointer applies as well.\n\nAll in all it should perfectly reasonable to use this for any procedure\nthat is not called inside a performance-sensitive tight loop.\n\n## Development\n\n### Windows\n\nTo build the demo open up MSVC Command Prompt and run `build.bat` in the repository folder.\n\n### Mac / Linux\n\nYou can build the demo by running `./build.sh`.\nBoth gcc and clang compilers are supported and you can\nset which one to use by providing a `CC` environment variable:\n\n```\nCC=clang ./build.sh\n```\n\n## License\n\nCopyright (c) 2021 Dmitriy Kubyshkin\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge,\npublish, distribute, sublicense, and/or sell copies of the Software,\nand to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\nOR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrassator%2Fdefer-for-c","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrassator%2Fdefer-for-c","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrassator%2Fdefer-for-c/lists"}