{"id":13846351,"url":"https://github.com/Qqwy/c_exceptional","last_synced_at":"2025-07-12T07:32:37.003Z","repository":{"id":150733392,"uuid":"122076419","full_name":"Qqwy/c_exceptional","owner":"Qqwy","description":"A simple Exception-handling library for C99, that uses some fancy macros for true try{...}catch(err){...}finally{...} syntax!","archived":false,"fork":false,"pushed_at":"2018-05-18T19:26:18.000Z","size":151,"stargazers_count":33,"open_issues_count":1,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-02-17T10:36:13.986Z","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":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Qqwy.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":"2018-02-19T14:46:52.000Z","updated_at":"2024-05-30T04:34:09.945Z","dependencies_parsed_at":"2023-08-30T09:17:14.109Z","dependency_job_id":null,"html_url":"https://github.com/Qqwy/c_exceptional","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Qqwy%2Fc_exceptional","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Qqwy%2Fc_exceptional/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Qqwy%2Fc_exceptional/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Qqwy%2Fc_exceptional/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Qqwy","download_url":"https://codeload.github.com/Qqwy/c_exceptional/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225807261,"owners_count":17527221,"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","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":"2024-08-04T18:00:30.774Z","updated_at":"2024-11-21T21:30:26.078Z","avatar_url":"https://github.com/Qqwy.png","language":"C++","funding_links":[],"categories":["C language extensions"],"sub_categories":[],"readme":"# Exceptional\n\nA simple Exception-handling library for C99 and up, that uses some fancy macros for true `try{...}catch(err){...}finally{...}` syntax!\n\n\nFirst, include `exceptional/exceptional.h` in your code.\n\nThen, use the `try { ... }` macro (combined with `catch { ... }` and/or possibly `finally { ... }`) to guard against errors. \n\nImplemented using Wonderful Black Ma(cro)gic. It is written in this convoluted style to ensure that you can use the following syntax:\n\n```C\ntry {\n  // some code here\n  if(something_is_wrong)\n    throw(error_code);\n  // some code that would only be executed if not thrown\n} catch(error_code) {\n  // Handle error here in any way you want.\n} finally {\n  // Runs regardless of catching/throwing.\n}\n```\n\n## Usage Notes:\n\n- Don't use return statements inside a `try`, `catch` or `finally` block, because it will forego the proper cleanup of the exception state. Just return after the end of the finally block and everything will be fine :-) .\n- When altering a variable that was introduced in the same function but outside the `try/catch/finally` block, be sure it is marked as `volatile`. This is because Exceptional is implemented using `setjmp`+`longjmp`, which might clobber the variables' values unless they were marked like this. (While `gcc` and other common comilers seem to do the right thing even when `volatile` was not used, you should not depend on it).\n- Re-throwing from within a catch-block now is fully supported! (**Hooray!**) The related finally block will be run first before bubbling the exception up the stack.\n\n**Truly exceptional, isn't it?**\n\nPost Scriptum: [By looking at the Compiler Explorer](https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAKxACZSAbAQwDtQB9T5UgZ1QFdiyTCADkAUloBmPADMWWWQGpsADQDC2AAoAVAJIB5AHIBBADLsAEu3EAGE5KmK8LTCo3b9x81Zv27DtIuyAz8WEriUuo8BOgMeABGAHQIkdgBjsGh4ZHRsXioKWkZQSwhYW65McQuwEVS6f7%2BpeU5UTyYBFQAtgAO9Y0O9gD0w0oAIpiyLm4ECHg8SkRKvTUsBEpYCfzASi6yJN1MBAUsSkwJAhsxTMgA1koA7i74bMP8LM8KtUklMrKKCbYABCAFUAOLsNSaXSGUxmAJKCLSZyuJRQgAewl6J1QLCYDHYWx27FWLgIECSVIAlEpZGT1rIIDEsMQyMjaNgsZgcacCSAOej2AA1EzsEwAJXBAGVONTIsC/pgGB1EcinFMZuiudjcfjCcTgKS1hSqUlaQqld9ZBlmhrpmjMbq%2BYSzHojNh2GYTMDsBY9ABZLRmCAY0hKACetKdPL1BK9F2V7HVjiUGJT0kjf1RbhjvLx8bdHq9Pr9ofDUe13Pz%2Bq97s93t9/qDIbDkflTRMmAxBEwxDOPV67G2yjzccJmBYADdLfZu73%2B3t1lXnQXCQRiBHhwxUPd2K4YrV2GgPgRZ0MTMMAFRq6UEJjEAiLJhLTcAWgSO/u4ZcT3myAQSMBCUZBWCUfgOgiAA2Ww5mIVBHnEGCllQJQqH4PolCuLDlEIc4FCUBBWDiNw%2B3g4geF%2BTskT0PoGEwbpJ17dBwJ4WolAAdTxVlZH4BglGBZh7iUAMmAgZB4OpYA8GQJIlD0DYFieGoCF7M5fzmJS0GnVBQmYpQYgjeiUKUSceEEWYiI2CNgNAs4IMstwDgYHcvl2HgI3WJgMRAW0TCRJDbEC4L7CRDcIwiAB2RVQqRJRRgM1BGJAjA3AQPtMDVJE5GZJLOnmNh2AWdhHngtgO38uKwoQeDHggMiSGPVL5SkGLKqRBK%2BGStBwjmY4ngEBgWLxBgIoSUiMUwZB%2BH0uQlBYVANjghCWDVcRIvGEDjgA%2Bq2UanrMAtaKsvisZLGI4yGuIQiMqXfCIseJgIps/gnlYAgqMq9bNodAlRqitqqoSiUPkWYhMGAB8SJ4RZUGUUCCAA2phmWtzPoCja1pg4LseoiZUIW3tfLxt98ZYMBRA2BylHBghBDOG5e0Y9ZFhcNjevmRZP13O5w3G0Dqbw54XLpEgIdQuY3BCTBWH4XocKWdLTOrPUDPvXt0aUUmOPSs5wbfVH2NkeDuieQgCug2wEYAwLw0ly3fpciNAo/L8HmF/jprZJj/v3Rbk2ID45OlVC2d7Jh0HDfXUbpE2zc0s57cd0bXZ5pQIBIc5ZAXRXZk3QimEWB0FnS9BqR/ZRwYAR34PBwfQT6/KRSZugjQ9ZAjdj7cE24HlE6TkGJi8qoARjkji3Ee5cuswPFZlQ8bzk/eeVkL58lG54TM7Yth6LfRmGKYrOc9Kwgu6Vo4JMKJQdE5pRGNYRZ7cv%2BCDIQQb0BOphaWLnhAOeOY%2BFLY5Q3PwQ6IV2ob1pNKYIk9J7vRMugVCM8E67CYNnPsislKbweERMGnR6aYEjnsa478%2BIsUXmzPA4Q4bnCUDuVA/QTrIFpDoVCRw7huHMuDRW/V7YxH4LIZQ6CFyPWIOgVmsMWD/UDmcdgIi%2BzJntjg8Mjw3CuCISZDhXCLK8KWkrFwU4Hx4AQUpfAQiMrLkeLrXO9DUCML2GDD4otrr8KmtxJYeBGKayRLQOSt8lIEj4PfGWLAn5WSeFLVghMlwbgwPwYQ90UphNAcgfR/VJwSPjoBF8wVMbIQEBRZUU5MCUROqTPQyg1FvWXMsWR98%2BInF6MZeIB4FYHXDA5IeVUcZBVxpAnKI95THVih1MYL1roHROsARaqFmDjQYOeHpG1TIqkyqM%2BhiYGDdLir0iBVUpByVBCwA4j4PjHGVBGO2ETtLVASRsJBpT5qLXOC5BCrETLkngugBJ6jMCPCUEYmoFx6I8D5lNJg1NJYPQ/lhaREVuwLEUmE6hjlgE2hghTLmGAIz7zQL0TAPiBIzUiVtBm95Hx0NOW%2BBh8tiKsTcIQVmLAz4EjwAAL0wcsCSMtex0NcACoFJjl5LLigAFn8Xfd%2BaiSnXUeYsB%2BicInVMwObTBGiWIvmlrKt6EVljaIMropOJAaX2PljERhYKsLXWqRqkyRESlUpcASJQFNf4FWABTAyU1VZ8KVrKvVjCdkBWxqGoKGzrF4HohAIZJ0cq2COoDOK7qiHsHmcqYNG9wZMDuKKjGm1lSqg2QlbSU5dIzU0QfZmT49GxO%2Bb8wFxiQVPIgkbE1tKynFrGAAnJ1w8orFQOSJc7M3AvgPPpaltLM0zOWCm9AaatnnhOgAVn8ahMyRqInP1uK/OyG83AORYr%2BbojS8DNLcF%2BY4pwrW2swJo/VOa3CFM2cvRYHw8A10JSdJEAAxTOmkrX20CmOF0dZiyNjLPiRi4ZOBFk9OweUyEX6hzfR0BuWM%2BmYYCFeYY2ZNRonCn%2BKNmAY20iquRijlGqPUZowFZd6g41MgTetYEtG2PsY42x8Q9GTogbXGBhspYQzhW3Dzdgc6YMCblAKTj1HuMMY2UiBI2bc2tVk%2BpjTcmeMbO%2BqsyCmmDOGYiNpyBSJTnUD6MOQRK5YygcnFOYcvc5aWlamRozdGFOmbivGxN7m/M0fk9%2BuKfHaxwZLE2CAImcHsA%2BF8YhsH6zSfc4FxT5G3xvhC/GKLbt9ylJOIVE86wFRGZS15qqjFujIF6BGCAmWJzThgzqWz/H7OOfuHLcMbFOVwws0OEc1IWqsdKzRurRJMDbCNAyCkkhaDHLi%2BxG49wBSSGXb0eTq1aD0GRFBUbrWEhOd6IN4znmaMztQqNsLEHhOblE3uCTQowsIeK%2Bx4blHvqFrcP5r7b2TM0fM0O3bKtThNTaJtIKrUFQWl%2B7R/7y5AerhYLdu4RIFi9G2ula6kQwcueBG5jzQWqORujUM77yXoccZyvD5riPov4B4GjxGGO8dUde7Js7NmayFkS1dyLN3ouxZeJJx7R2fsnc4x9vYTJY3RVJ%2Bp1nnHRuGmNOSCAM2OIvAW/eJbyJVvrZm%2BGSQO2muc/qw5/b7XDvFflxxirVWau7enG1u4HWOfjnYPZzrHLZ5MkHFZ2QA2rfk845IRUtBgSjey2J8dR5CtnjUy9oPHH2cXe50J3nW5LjoC3B0bS86iIMFkELxLT34/49SwFlZEvZcGet7RlP4G09RZxewHP3F2D58Lw94v1IZNabF7J8zVOawg8qFITaHQuh9Fq8bt39mjtD71EjlH9P0eYNyEoKQVuw8h4X8D2nqPV/ECh/39TlOZ92aB3iEfEQx9Y6ULYbbhvXcX4R0vunDOAJr9v2P%2B/FUAjXjVACS5jdkcThX%2Bm7CmgrSPSqTcFpkIRYmNiSjoUCh3DYEHECnTlRjOASAikClRkClpFWEwCnAKAglGkblilvkqBglORdluVSQ2ERRiGZRuh4WWA3TYIiRfGTlxRwTNhFkXnqTmjwkCXQCwE1X0VIgUE%2BhwzwwdCiUZ3qkvxYFpCr2r1o3l1hw2FG1phqhWnd2UOvzv3B1Y13yv33xX0Zy/3UA30h2OyCy0OVgRxv02jMMRymTUzcLfwPysMxyiFsLUxDx33Pxa0MIsI/yZ3sPL0l2n2UPjG7Ff3CMPx1yUFoBcOMPiivCUE5Vfn/UeFQhw181ryqjPziInEMIOkf1oCgmf1CMSJy3f2SKx2MKKMT0o0V3GxJCm1V023V2%2BDYC2kZzVl7mW1oF13ow2y20NwdzNwOyO2KPIx0PylqkRwSOpyMJ/wn0HFiIR3iOnHmLaIoxyjADACWKwIMNfwOl81kwWIo2TxCNC1Twi2tgQGHBxSL2LBL1Ywo1uN2RWXUO%2B1%2BPezWRiK8MqMNyfy8KSN8PSJ/1oGGSG0OMWIePjCV26Jmzmw1wGJeOGO1xWzWwmP122xmKdzlgOJPyo1t2qx2Opz2KnEazKPd0d3N2d16E926x90s363JIJ3I1KN2MJF0JWIuPWKuJY001%2BKqg6Im2V3WB6NoAlEwANj0LclMj2kxzGM1QwWuh4I3hAMeicVWkJM2wZIFPYCFP0LWOHzFMCKRIo1RhpJN3NOWMtIqOamey4ztL%2BM2gBK%2ByBP%2BN9L9KRN0wlx80DI0wWPr0E2ePRzeKzw%2BPgx7z8gANij0DKHBmrXCTcEaJhPYLCU3T9ScmdSdlTmEiUlcB1QgOmn0m6DFl4TODxESV/BfFqlIDVHBkhnEVBVhiqXSklmulyRgheJdj4KYJrUzkJgoMqioKXFaWoNsCpOdmQiUgxxXg4MsgyRKXUhgLQgwnlmwloUHNsB4JHJAIgHiE4T/EnBpiVMNnKmuQmmcIPlAMPBFjgP7HvVDnHJqGkn1EBT7DYjxBkNwztBzDpGLPAJBP5NpPKPqLExzM/z8PGDvxHiqJqMXMdNnwa1qNrD2wO3ZO916z9wGz/xGBvEoJVOfDOCtNVhwNYnYhQLxGAHQJgk1h1mvNAhck0SuBHQVlYFwJgnClPJ5lUSjX4gXG6GdT5XtlWFQGAGICYFNh7SASuhCRhiYGAC/XsFkNAvw0slqiUIR1pCQQBn83l2ONOJRPXD5xy2jwKwEHWARNFwcKmyZBZDIjbM22OQFmAAQEYOUNGOXU/mNK2xotOBF1r0RQpDUD0B0HYB/RMD0DMFBAlGwBF0BKD103DITxP2lK6JNHlNvlqnYjCrxECuCvUEmPDFKpUOe3l1QOYqnxmOquUPSr7zWhWSJzcAgATWyvI1Kz8kcDAotIBQdM4CspFOtPdM7CtHMVOmhE8DhB8GsGTLGGBEEVkC5VQk4R5CcOp0VmKoGIPk%2Bl9xHBwrpPPASlBDQxMgJBznGgdWfVoTwJVIwOsWvMPSwhml4sPMtiEpglLLuE%2BgBwmsjz3DsqNFjxcPvyXXsCHSOBcAgARLVCHQOFQmMNhuHhWBNCZBmzfDSCUBgTojzgjGGF1OUoUoWEyhCsGzVEIxYxOlcvlLTN4qEpprzQOoQggDFXhI5qZpm3UHRwFGlDISGmeQ2Cmxm1ptil011IZo2X5s2x/QgojGFtFooVgOcQUVcU3D1022lq%2BkxhmtinfLOBMIyCNpMFEHLm2VEGXVEFIBYDEFsAdtQDEBsL4EEESUcFoAdoIGdutvLjuBAGXVsEYDEDFQdqdtEBdtIDdtEAdp4BADDv9pjuttIDgFgCQDQD6GIzIAoHEiSl6DzpQGAEinoGmAYAXCTogASADtIASGdU3DEBHgdpzurQMHhXrqwCOF3hEFEFbtIHwHBjSTwBKSTrTtICrIrRbodvJAzUno3C8QDpttYA4C4EYESCTsgHLkYT1AnrfAMCkETsKWEDoBtrEHtsdvrvjoxAAA4oI3woIxUlBgBkBkAlBIokg0iIBcBCBM4fbwx1Ai6871QSd1A/aV7y50oI4%2BxKAg6Q6w7bbI7r7J747E7k7SBU6XaBtw7RBfbUHY70GsGoHSBZVAKnaxUgA%3D%3D) it can be seen that the 'black macros' that Exceptional consists of are completely optimized away, only keeping the stack winding/unwinding and conditional jump checking in place.\n\n\n# Running Tests\n\n1. Clone or download the repository.\n2. Make sure that besides `gcc` you have `nodejs` and the node package manager (`npm`) installed on your system, because tests are run using the tool `urchin`.\n2. Run `make test`. This will:\n  - auto-install `urchin` if it was not installed yet, \n  - Compile and link all C-files in the `/test` folder\n  - Run `urchin` on these executables. Urchin tests are successful if the exit code of the executable == 0.\n  - Clean up the generated executables afterwards.\n\n\n# Planned Future work:\n\n1. Rewriting the throwing/catching logic because the way a values is currently read from `setjmp` is not fully spec-adherent (i.e. it relies on undefined behaviour), although all common compilers allow it.\n2. I am currently thinking about adding support to throw any (user supplied) structure rather than just integers.\n\nHow does it work? Or: Demystifying the Black Magic:\n====================================\n\n_For a more gradual introduction to these concepts, read ['Metaprogramming custom control structures in C'](https://www.chiark.greenend.org.uk/%7Esgtatham/mp/) by Simon Tatham, which is really good!_\n\n1. We want someone to be able to pass a block or single-statement after writing the macro. This means the macro should\n  a) finish with an `if(true)`\n  b) Since we want to do something after this block has returned, it should be inside of a loop.\n  c) To make sure that the stuff afterwards is only run _after_ the block, we need to make sure that the invariant is different when the loop is run for the second time.\n    An example:\n    ```C\n    for(int var = 0;var \u003c 2; ++i)\n      if(var == 1) {\n        //stuff to run afterwards\n      } else\n    ```\n2. This also means that we cannot introduce any construct that ends with a `}` ourselves.\n  - If we want to run multiple lines of code, use:\n  ```C\n  if(1){\n    // your code\n    goto label;\n  } else\n    label:\n    //Continue statements that do not end with `}` here.\n  ```\n3. Unfortunately, that construct does not allow us to introduce new variables, because they would only exist inside the `if`'s body-scope.\nBut we can start a for-loop and use its initializer to create a new variable;\n4. This however does mean that we either need a clever way to make sure the for-loop stops, or we need to have a final 'finishing' section at the very top:\n```C\n  while(1)\n    if(0) {\n      finished_label:\n      break;\n    } else\n      for(int some_var;;)\n        for(int some_other_var;;)\n          // with at some point inside a nested for-loop:\n            if(something_only_true_when_user_code_already_ran)\n              goto finished_label;\n```\n\n5. To ensure that the macro can be used in multiple locations, we need to make our lables unique.\n  For this, the `LINE_LABEL(name, __LINE__)` macro is used.\n\nDisclaimer\n============\n\nThis was written to test the limits of C's macro system as well as my own understanding of low-level system languages.\n\nWhile it seems to work in the limited tests that I ran on it, it should by no means be considered highly stable.\n\nEnjoy!\n\n\nAttribution\n=============\n\nI want to thank DSMan195276 [whose post on Reddit](https://www.reddit.com/r/C_Programming/comments/6o7kpb/raii_in_c_cleanup_gcc_compiler_extension/dkgzztq/) I came across,\nwhich taught me most of the macro-twiddling strategies used in this library.\n\nHe has since pointed me to this marvellous resource, which explains a lot of these techniques in more detail: https://www.chiark.greenend.org.uk/%7Esgtatham/mp/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FQqwy%2Fc_exceptional","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FQqwy%2Fc_exceptional","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FQqwy%2Fc_exceptional/lists"}