From 31c41be1ef8a31901b504edc1ebbbb3e99f5dc71 Mon Sep 17 00:00:00 2001 From: z3rOR0ne Date: Sun, 26 Feb 2023 18:32:52 -0800 Subject: [PATCH] :memo: Updated rss feeds and bookmark --- .config/newsboat/my_urls | 2 + .config/newsboat/rss/dudemanguy.xml | 435 ++++ .config/newsboat/rss/joren.xml | 3419 +++++++++++++++++++++++++++ aliases | 3 +- 4 files changed, 3858 insertions(+), 1 deletion(-) create mode 100644 .config/newsboat/rss/dudemanguy.xml create mode 100644 .config/newsboat/rss/joren.xml diff --git a/.config/newsboat/my_urls b/.config/newsboat/my_urls index 79ceac7a..287fd8a9 100644 --- a/.config/newsboat/my_urls +++ b/.config/newsboat/my_urls @@ -32,3 +32,5 @@ file://./rss/1Upsmanship.rss file://./rss/chris_titus_tech.xml file://./rss/linux_experiment.xml file://./rss/qqwithsorenanddaniel.xml +file://./rss/dudemanguy.xml +file://./rss/joren.xml diff --git a/.config/newsboat/rss/dudemanguy.xml b/.config/newsboat/rss/dudemanguy.xml new file mode 100644 index 00000000..6e8fdf72 --- /dev/null +++ b/.config/newsboat/rss/dudemanguy.xml @@ -0,0 +1,435 @@ + + + +Dudemanguy's Musings +All Posts +https://dudemanguy.github.io/blog/ + + + 四人囃子 - 一触即発 + 四人囃子 - 一触即発 (Album Review) + https://dudemanguy.github.io/blog/posts/2022-08-13-yonin-bayashi-isshoku-sokuhatsu/yonin-bayashi-isshoku-sokuhatsu.html + Post 71 + + + Wayland Isn't Going to Save The Linux Desktop + Wayland Isn't Going to Save The Linux Desktop (Article) + https://dudemanguy.github.io/blog/posts/2022-06-10-wayland-xorg/wayland-xorg.html + Post 70 + + + Gothic/Post-punk Visual Kei of the 90s + Gothic/Post-punk Visual Kei of the 90s (Article) + https://dudemanguy.github.io/blog/posts/2021-03-16-gothic-post-punk-visual-kei/gothic-post-punk-visual-kei.html + Post 69 + + + Time for a Change + Time for a Change (Article) + https://dudemanguy.github.io/blog/posts/2021-03-16-time-for-a-change/time-for-a-change.html + Post 68 + + + Top Ten Albums of 2019 + Top Ten Albums of 2019 (Article) + https://dudemanguy.github.io/blog/posts/2020-02-17-top-ten-albums-of-2019/top-ten-albums-of-2019.html + Post 67 + + + s6 Deserves More Love + s6 Deserves More Love (Article) + https://dudemanguy.github.io/blog/posts/2019-12-19-s6-love/s6-love.html + Post 66 + + + Spotify is Cancer + Spotify is Cancer (Article) + https://dudemanguy.github.io/blog/posts/2019-12-11-spotify-is-cancer/spotify-is-cancer.html + Post 65 + + + Unexpect - In a Flesh Aquarium + Unexpect - In a Flesh Aquarium (Album Review) + https://dudemanguy.github.io/blog/posts/2019-12-10-unexpect-flesh/unexpect-flesh.html + Post 64 + + + Unexpect - _We, Invaders + Unexpect - _We, Invaders (EP Review) + https://dudemanguy.github.io/blog/posts/2019-11-22-unexpect-we-invaders/unexpect-we-invaders.html + Post 63 + + + Gyze - Asian Chaos + Gyze - Asian Chaos (Album Review) + https://dudemanguy.github.io/blog/posts/2019-11-21-gyze-asian-chaos/gyze-asian-chaos.html + Post 62 + + + IRON ATTACK! - Japonism + IRON ATTACK! - Japonism (Album Review) + https://dudemanguy.github.io/blog/posts/2019-11-21-iron-attack-japonism/iron-attack-japonism.html + Post 61 + + + A Fresh Start + A Fresh Start (Article) + https://dudemanguy.github.io/blog/posts/2019-11-20-a-fresh-start/a-fresh-start.html + Post 60 + + + Devil Within - Dark Supremacy + Devil Within - Dark Supremacy (Album Review) + https://dudemanguy.github.io/blog/posts/2019-05-07-devil-within-dark-supremacy/devil-within-dark-supremacy.html + Post 59 + + + ARESZ - Beat Blast Spiral + ARESZ - Beat Blast Spiral (Album Review) + https://dudemanguy.github.io/blog/posts/2019-05-02-aresz-beat-blast-spiral/aresz-beat-blast-spiral.html + Post 58 + + + Lux Occulta - My Guardian Anger + Lux Occulta - My Guardian Anger (Album Review) + https://dudemanguy.github.io/blog/posts/2019-05-01-lux-occulta-my-guardian-anger/lux-occulta-my-guardian-anger.html + Post 57 + + + Valthus - Remains of Memory + Valthus - Remains of Memory (EP Review) + https://dudemanguy.github.io/blog/posts/2019-05-01-valthus-remains-of-memory/valthus-remains-of-memory.html + Post 56 + + + Hidden - Embalm 〜Enbalm After 20 Years〜 + Hidden - Embalm 〜Enbalm After 20 Years〜 (Album Review) + https://dudemanguy.github.io/blog/posts/2019-04-26-hidden-embalm/hidden-embalm.html + Post 55 + + + La'cryma Christi - Dwellers of a Sandcastle + La'cryma Christi - Dwellers of a Sandcastle (Album Review) + https://dudemanguy.github.io/blog/posts/2019-02-18-la'cryma-christi-dwellers/la'cryma-christi-dwellers.html + Post 54 + + + Galneryus - Under the Force of Courage + Galneryus - Under the Force of Courage (Album Review) + https://dudemanguy.github.io/blog/posts/2019-02-08-galneryus-courage/galneryus-courage.html + Post 53 + + + Luna Sea - LUV + Luna Sea - LUV (Album Review) + https://dudemanguy.github.io/blog/posts/2018-11-01-luna-sea-luv/luna-sea-luv.html + Post 52 + + + Terror Squad - the wild stream of eternal sin + Terror Squad - the wild stream of eternal sin (Album Review) + https://dudemanguy.github.io/blog/posts/2018-10-18-terror-squad-wild-stream/terror-squad-wild-stream.html + Post 51 + + + Shellshock - 肆 - SHI - + Shellshock - 肆 - SHI - (Album Review) + https://dudemanguy.github.io/blog/posts/2018-08-07-shellshock-shi/shellshock-shi.html + Post 50 + + + Lovebites - The Lovebites EP + Lovebites - The Lovebites EP EP review + https://dudemanguy.github.io/blog/posts/2018-07-24-lovebites-the-lovebites-ep/lovebites-the-lovebites-ep.html + Post 49 + + + Regnum Caelorum et Gehenna - Dimersity 03 : Verum cur non Audimus + Regnum Caelorum et Gehenna - Dimersity 03 : Verum cur non Audimus (Album Review) + https://dudemanguy.github.io/blog/posts/2018-07-19-regnum-dimersity-03/regnum-dimersity-03.html + Post 48 + + + Hollow Mellow - Reincarnation + Hollow Mellow - Reincarnation (Album Review) + https://dudemanguy.github.io/blog/posts/2017-09-15-hollow-mellow-reincarnation/hollow-mellow-reincarnation.html + Post 47 + + + Light Bringer - Heartful Message + Light Bringer - Heartful Message (EP Review) + https://dudemanguy.github.io/blog/posts/2017-03-05-light-bringer-heartful-message/light-bringer-heartful-message.html + Post 46 + + + 電気式華憐音楽集団 - DETONATOR + 電気式華憐音楽集団 - DETONATOR (Album Review) + https://dudemanguy.github.io/blog/posts/2017-03-03-denkare-detonator/denkare-detonator.html + Post 45 + + + ARESZ - GRATING + ARESZ - GRATING (Album Review) + https://dudemanguy.github.io/blog/posts/2017-01-29-aresz-grating/aresz-grating.html + Post 44 + + + 黒夢 - 迷える百合達 ~Romance of Scarlet~ + 黒夢 - 迷える百合達 ~Romance of Scarlet~ (Album Review) + https://dudemanguy.github.io/blog/posts/2017-01-22-kuroyume-mayoeru-yuritachi/kuroyume-mayoeru-yuritachi.html + Post 43 + + + Versailles - The Greatest Hits 2007-2016 + Versailles - The Greatest Hits 2007-2016 (Album Review) + https://dudemanguy.github.io/blog/posts/2016-12-02-versailles-the-greatest-hits/versailles-the-greatest-hits.html + Post 42 + + + D - Neo culture -Beyond the world- + D - Neo culture -Beyond the world- (Album Review) + https://dudemanguy.github.io/blog/posts/2016-11-05-d-neo-culture/d-neo-culture.html + Post 41 + + + 黒夢 - 亡骸を・・・ + 黒夢 - 亡骸を・・・(Album Review) + https://dudemanguy.github.io/blog/posts/2016-11-05-kuroyume-nakigara-wo/kuroyume-nakigara-wo.html + Post 40 + + + D - Tafel Anatomie + D - Tafel Anatomie (Album Review) + https://dudemanguy.github.io/blog/posts/2016-10-29-d-tafel-anatomie/d-tafel-anatomie.html + Post 39 + + + Hizaki - Rosario + Hizaki - Rosario (Album Review) + https://dudemanguy.github.io/blog/posts/2016-10-29-hizaki-rosario/hizaki-rosario.html + Post 38 + + + Watchtower - Concepts of Math: Book One + Watchtower - Concepts of Math: Book One (EP Review) + https://dudemanguy.github.io/blog/posts/2016-10-24-watchtower-concepts-of-math/watchtower-concepts-of-math.html + Post 37 + + + 陰陽座 - 鬼哭転生 + 陰陽座 - 鬼哭転生 (Album Review) + https://dudemanguy.github.io/blog/posts/2016-10-22-onmyouza-kikoku-tenshou/onmyouza-kikoku-tenshou.html + Post 36 + + + Dir En Grey - Macabre + Dir En Grey - Macabre (Album Review) + https://dudemanguy.github.io/blog/posts/2016-10-22-dir-en-grey-macabre/dir-en-grey-macabre.html + Post 35 + + + Kamijo - Heart + Kamijo - Heart (Album Review) + https://dudemanguy.github.io/blog/posts/2016-08-31-kamijo-heart/kamijo-heart.html + Post 34 + + + MinstreliX - Memoirs + MinstreliX - Memoirs (Album Review) + https://dudemanguy.github.io/blog/posts/2016-08-28-minstrelix-memoirs/minstrelix-memoirs.html + Post 33 + + + Octaviagrace - Recollect Storia + Octaviagrace - Recollect Storia (EP Review) + https://dudemanguy.github.io/blog/posts/2016-08-26-octaviagrace-recollect-storia/octaviagrace-recollect-storia.html + Post 32 + + + Dir En Grey - Gauze + Dir En Grey - Gauze (Album Review) + https://dudemanguy.github.io/blog/posts/2016-08-20-dir-en-grey-gauze/dir-en-grey-gauze.html + Post 31 + + + Doom - Complicated Mind + Doom - Complicated Mind (Album Review) + https://dudemanguy.github.io/blog/posts/2016-08-19-doom-complicated-mind/doom-complicated-mind.html + Post 30 + + + Doom - Killing Field + Doom - Killing Field (Album Review) + https://dudemanguy.github.io/blog/posts/2016-03-14-doom-killing-field/doom-killing-field.html + Post 29 + + + 黒夢 - 生きていた中絶児・・・・ + 黒夢 - 生きていた中絶児・・・・ (EP Review) + https://dudemanguy.github.io/blog/posts/2016-02-05-kuroyume-ikkiteita-chuzetsuji/kuroyume-ikiteita-chuzetsuji.html + Post 28 + + + Jupiter - Topaz + Jupiter - Topaz (Single Review) + https://dudemanguy.github.io/blog/posts/2015-12-24-jupiter-topaz/jupiter-topaz.html + Post 27 + + + Jupiter - Blessing of the Future + Jupiter - Blessing of the Future (Single Review) + https://dudemanguy.github.io/blog/posts/2015-12-24-jupiter-blessing-of-the-future/jupiter-blessing-of-the-future.html + Post 26 + + + Hizaki - Dance with grace + Hizaki - Dance with grace (EP Review) + https://dudemanguy.github.io/blog/posts/2015-12-24-hizaki-dance-with-grace/hizaki-dance-with-grace.html + Post 25 + + + Hizaki - Maiden Ritual (EP Review) + Hizaki - Maiden Ritual (EP Review) + https://dudemanguy.github.io/blog/posts/2015-12-24-hizaki-maiden-ritual/hizaki-maiden-ritual.html + Post 24 + + + Mysterious Priestess - 夢国ノ義士 + Mysterious Priestess - 夢国ノ義士 (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-24-mysterious-priestess-mangan/mysterious-priestess-mangan.html + Post 23 + + + Mysterious Priestess - Agency of Fate + Mysterious Priestess - Agency of Fate (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-24-mysterious-priestess-agency/mysterious-priestess-agency.html + Post 22 + + + 人間椅子 - 無限の住人 + 人間椅子 - 無限の住人 (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-24-ningen-isu-mugen-no-juunin/ningen-isu-mugen-no-juunin.html + Post 21 + + + D - The Name of the ROSE + D - The Name of the ROSE (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-23-d-the-name-of-the-rose/d-the-name-of-the-rose.html + Post 20 + + + 陰陽座 - 魑魅魍魎 + 陰陽座 - 魑魅魍魎 (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-22-onmyouza-chimimouryou/onmyouza-chimimouryou.html + Post 19 + + + Gauntlet - Birthplace of Emperor + Gauntlet - Birthplace of Emperor (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-22-gauntlet-birthplace-of-emperor/gauntlet-birthplace-of-emperor.html + Post 18 + + + MergingMoon - Kamikakushi〜神隠し + MergingMoon - Kamikakushi〜神隠し (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-20-mergingmoon-kamikakushi/mergingmoon-kamikakushi.html + Post 17 + + + Versailles - Versailles + Versailles - Versailles (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-20-versailles-versailles/versailles-versailles.html + Post 16 + + + Art of Gradation - Concentration + Art of Gradation - Concentration (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-19-art-of-gradation-concentration/art-of-gradation-concentration.html + Post 15 + + + Versailles - Holy Grail + Versailles - Holy Grail (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-19-versailles-holy-grail/versailles-holy-grail.html + Post 14 + + + 人間椅子 - 二十世紀葬送曲 + 人間椅子 - 二十世紀葬送曲 (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-19-ningen-isu-nijuu/ningen-isu-nijuu.html + Post 13 + + + ARESZ - SKILL + ARESZ - SKILL (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-19-aresz-skill/aresz-skill.html + Post 12 + + + Versailles - Jubilee -Method of Inheritance- + Versailles - Jubilee -Method of Inheritance- (Album Review) + https://dudemanguy.github.io/blog/posts/2015-12-18-versailles-jubilee/versailles-jubilee.html + Post 11 + + + Dir En Grey - Missa + Dir En Grey - Missa (EP Review) + https://dudemanguy.github.io/blog/posts/2015-12-09-dir-en-grey-missa/dir-en-grey-missa.html + Post 10 + + + Gargoyle - 禊 + Gargoyle - 禊 (Album Review) + https://dudemanguy.github.io/blog/posts/2015-11-25-gargoyle-misogi/gargoyle-misogi.html + Post 9 + + + X Japan - Art of Life + X Japan - Art of Life (Album Review) + https://dudemanguy.github.io/blog/posts/2015-09-06-x-japan-art-of-life/x-japan-art-of-life.html + Post 8 + + + Octaviagrace - Resonant Cinema + Octaviagrace - Resonant Cinema (Album Review) + https://dudemanguy.github.io/blog/posts/2015-07-13-octaviagrace-resonant-cinema/octaviagrace-resonant-cinema.html +Post 7 + + + Loszeal - Ideal World + Loszeal - Ideal World (Album Review) + https://dudemanguy.github.io/blog/posts/2015-07-03-loszeal-ideal-world/loszeal-ideal-world.html + Post 6 + + + Vrain - Rendez Blue + Vrain - Rendez Blue (Album Review) + https://dudemanguy.github.io/blog/posts/2015-07-03-vrain-rendez-blue/vrain-rendez-blue.html + Post 5 + + + 愛狂います - 心臓。 + 愛狂います - 心臓。(Album Review) + https://dudemanguy.github.io/blog/posts/2015-04-20-aicle-shinzou/aicle-shinzou.html + Post 4 + + + Jizue - Novel + Jizue - Novel (Album Review) + https://dudemanguy.github.io/blog/posts/2015-03-12-jizue-novel/jizue-novel.html + Post 3 + + + Jupiter - The History of Genesis + Jupiter - The History of Genesis (Album Review) + https://dudemanguy.github.io/blog/posts/2015-03-02-jupiter-history-of-genesis/jupiter-the-history-of-genesis.html + Post 2 + + + Unexpect - Utopia + Unexpect - Utopia (Album Review) + https://dudemanguy.github.io/blog/posts/2010-07-02-unexpect-utopia/unexpect-utopia.html + Post 1 + + + diff --git a/.config/newsboat/rss/joren.xml b/.config/newsboat/rss/joren.xml new file mode 100644 index 00000000..c1ab1561 --- /dev/null +++ b/.config/newsboat/rss/joren.xml @@ -0,0 +1,3419 @@ +Jekyll2023-02-27T01:05:30+00:00https://blog.joren.ga/feed.xmlJoren-&gt;blogJorengarenarGOTOphobia considered harmful (in C)2023-02-26T00:00:00+00:002023-02-26T00:00:00+00:00https://blog.joren.ga/gotophobia-harmful<aside> + <p><strong>gotophobia</strong> – fear of <code>goto</code> statement, usually caused by misunderstanding +and lack of context of stories from dark ages of programming. Programmers with +gotophobia tend to make their code less readable just to avoid using <code>goto</code>.</p> +</aside> + +<p>Everybody and their grandpa knows (the meme title of) Dijkstra's +<a href="https://dl.acm.org/doi/epdf/10.1145/362929.362947"><em>Letters to the editor: go to statement considered harmful</em></a> +(submitted under the title: <em>A case against the goto statement</em>), +but most forget the context of the 60s in which it was written, +things we take for granted were a novelty back then.</p> + +<p>A lot programmers learnt the craft in a world where <code>goto</code> was the main method +of flow control; even in structured languages it was easy for them to fall back +on the learned bad habits and techniques. +On the other hand, today we have the very opposite situation: programmers not +using <code>goto</code> when it's appropriate and abusing other constructs, what ironically +makes code only less readable. They overfocus on the <em>WHAT</em> ("remove <code>goto</code>") +rather than the <em>WHY</em> ("because it improves readability and maintainability").</p> + +<p>Academic teachers parroting "<code>goto</code> evil" while not really understanding the +language they teach only worsens the matter [speaking from experience]. Because +who needs to learn good practices and discipline, right? It's obviously better +to just ignore the topic entirely and let the students later wonder why they get +<a href="https://www.explainxkcd.com/wiki/index.php/292:_goto">attacked by velociraptors</a>.</p> + +<blockquote> + <p>A "goto" is not, in and of itself, dangerous – it is a language feature, +one that directly translates to the jump instructions implemented in machine +code. Like pointers, operator overloading, and a host of other "perceived" +evils in programming, "goto" is widely hated by those who've been bitten by +poor programming. Bad code is the product of bad programmers; in my +experience, a poor programmer will write a poor program, regardless of the +availability of "goto."</p> + + <p>If you think people can't write spaghetti code in a "goto-less" language, I +can send you some <em>lovely</em> examples to disabuse you of that notion. ;)</p> + + <p>Used over short distances with well-documented labels, a "goto" can be more +effective, faster, and cleaner than a series of complex flags or other +constructs. The "goto" may also be safer and more intuitive than the +alternative. A "break" is a goto; a "continue" is a "goto" – these are +statements that move the point of execution explicitly.</p> + + <p>~ <a href="https://lkml.org/lkml/2003/1/12/245">Scott Robert Ladd</a></p> +</blockquote> + +<p>Linux kernel is one thing, but if even such restrictive coding standard +as MISRA C (2012 edition) can downgrade the prohibition on <code>goto</code> from +<em>required</em> to <em>advisory</em>, I think in regular code we can safely use <code>goto</code> +in judicious manner. Thus I want to present some situations and patterns +where <code>goto</code> could be acceptable (perhaps the best?) choice and you could +maybe want to <em>consider</em> using it.</p> + +<aside> + <p><strong>Resources</strong></p> + + <ul> + <li><em>The C Programming Language, 2nd ed.</em> by Kernighan &amp; Ritchie</li> + <li><a href="https://en.wikipedia.org/wiki/Goto#Common_usage_patterns">Goto # Common usage patterns - Wikipedia</a></li> + <li><a href="https://stackoverflow.com/q/24451/10247460">Are there any legitimate use-cases for "goto" in a language that supports loops and functions? - Stack Overflow</a></li> + <li><a href="https://beej.us/guide/bgc/html/split/goto.html">Beej's Guide to C Programming: <code>goto</code></a></li> + <li><a href="https://hal.inria.fr/hal-02383654/file/ModernC.pdf">Modern C</a> by Jens Gustedt</li> + <li><a href="https://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c">Using goto for error handling in C</a></li> + <li><a href="https://dl.acm.org/doi/epdf/10.1145/356635.356640">Structured Programming with <em>go to</em> Statements</a> by Donald E. Knuth</li> + <li><a href="https://www.reddit.com/r/C_Programming/comments/g3juie/error_handling_using_goto/">Error handling using goto : r/C_Programming</a></li> + <li><a href="https://www.kernel.org/doc/html/v6.2/process/coding-style.html#centralized-exiting-of-functions">Linux kernel coding style</a></li> + <li><a href="https://www.cprogramming.com/tutorial/goto.html">When to use Goto in C - Cprogramming.com</a></li> + <li><a href="https://alvaro-videla.com/2015/02/programming-myths.html">Harmful GOTOs, Premature Optimizations, and Programming Myths are the Root of all Evil</a></li> + <li><a href="https://stackoverflow.com/q/245742/10247460">Examples of good gotos in C or C++ - Stack Overflow</a></li> + <li><a href="https://www.youtube.com/watch?v=8bmEhtMVrhk">Should you ever use a goto? - Jacob Sorber - YouTube</a></li> + <li><a href="https://chidiwilliams.com/post/goto/">GOTO Reconsidered</a></li> + <li><a href="http://web.archive.org/web/20090320002214/http://www.ecn.purdue.edu/ParaMount/papers/rubin87goto.pdf">"GOTO Considered Harmful" Considered Harmful</a></li> + <li><a href="https://www.reddit.com/r/C_Programming/comments/wimvdf/when_is_it_appropriate_to_use_goto/">When is it appropriate to use GOTO? : r/C_Programming</a></li> + <li><a href="https://dl.acm.org/doi/pdf/10.1145/800194.805859">Programming With(out) the GOTO</a></li> + <li><a href="https://geometrian.com/programming/tutorials/gotogood/index.php">Ian Mallett - Tutorials: The goto Statement is Good</a></li> + <li><a href="https://wiki.sei.cmu.edu/confluence/display/c/MEM12-C.+Consider+using+a+goto+chain+when+leaving+a+function+on+error+when+using+and+releasing+resources">MEM12-C. Consider using a goto chain when leaving a function on error when using and releasing resources - SEI CERT C Coding Standard</a></li> + <li><a href="https://stackoverflow.com/q/788903/10247460">Valid use of goto for error management in C? - Stack Overflow</a></li> + <li><a href="https://lkml.org/lkml/2003/1/12/126">LKML: Rob Wilkens: Re: any chance of 2.6.0-test*?</a> + <ul> + <li><a href="https://web.archive.org/web/20130521051957/https://kerneltrap.org/node/553/2131">Linux: Using goto In Kernel Code | KernelTrap</a></li> + <li><a href="https://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto-in-Linux-Kernel-Code/">Using Goto in Linux Kernel Code | Koblents.com</a></li> + </ul> + </li> + </ul> +</aside> + +<ul id="markdown-toc"> + <li><a href="#errorexception-handling--cleanup" id="markdown-toc-errorexception-handling--cleanup">Error/exception handling &amp; cleanup</a> <ul> + <li><a href="#goto-less-alternative-1-nested-ifs" id="markdown-toc-goto-less-alternative-1-nested-ifs"><code>goto</code>-less alternative 1: nested <code>if</code>s</a></li> + <li><a href="#goto-less-alternative-2-if-not-then-clean" id="markdown-toc-goto-less-alternative-2-if-not-then-clean"><code>goto</code>-less alternative 2: if not then clean</a></li> + <li><a href="#goto-less-alternative-3-flags" id="markdown-toc-goto-less-alternative-3-flags"><code>goto</code>-less alternative 3: flags</a></li> + <li><a href="#goto-less-alternative-35-so-far-ok-flag" id="markdown-toc-goto-less-alternative-35-so-far-ok-flag"><code>goto</code>-less alternative 3.5: so-far-ok flag</a></li> + <li><a href="#goto-less-alternative-4-functions" id="markdown-toc-goto-less-alternative-4-functions"><code>goto</code>-less alternative 4: functions</a></li> + <li><a href="#goto-less-alternative-5-abuse-of-loops" id="markdown-toc-goto-less-alternative-5-abuse-of-loops"><code>goto</code>-less alternative 5: abuse of loops</a></li> + </ul> + </li> + <li><a href="#restartretry" id="markdown-toc-restartretry">Restart/retry</a> <ul> + <li><a href="#goto-less-alternative-loop" id="markdown-toc-goto-less-alternative-loop"><code>goto</code>-less alternative: loop</a></li> + <li><a href="#less-trivial-example" id="markdown-toc-less-trivial-example">Less trivial example</a> <ul> + <li><a href="#goto-version" id="markdown-toc-goto-version"><code>goto</code> version</a></li> + <li><a href="#goto-less-version" id="markdown-toc-goto-less-version"><code>goto</code>-less version</a></li> + </ul> + </li> + </ul> + </li> + <li><a href="#common-code-in-switch-statement" id="markdown-toc-common-code-in-switch-statement">Common code in <code>switch</code> statement</a> <ul> + <li><a href="#goto-less-alternative-1-functions" id="markdown-toc-goto-less-alternative-1-functions"><code>goto</code>-less alternative 1: functions</a></li> + <li><a href="#goto-less-alternative-2-ifs" id="markdown-toc-goto-less-alternative-2-ifs"><code>goto</code>-less alternative 2: <code>if</code>s</a></li> + <li><a href="#goto-less-alternative-3-interlacing-if-0" id="markdown-toc-goto-less-alternative-3-interlacing-if-0"><code>goto</code>-less alternative 3: interlacing <code>if (0)</code></a></li> + <li><a href="#goto-less-alternative-capturing-lambda" id="markdown-toc-goto-less-alternative-capturing-lambda"><del><code>goto</code>-less alternative: capturing lambda</del></a></li> + </ul> + </li> + <li><a href="#nested-break-labeled-continue" id="markdown-toc-nested-break-labeled-continue">Nested <code>break</code>, labeled <code>continue</code></a></li> + <li><a href="#simple-state-machines" id="markdown-toc-simple-state-machines">Simple state machines</a></li> + <li><a href="#jumping-into-event-loop" id="markdown-toc-jumping-into-event-loop">Jumping into event loop</a> <ul> + <li><a href="#goto-less-alternative-1-guard-flag" id="markdown-toc-goto-less-alternative-1-guard-flag"><code>goto</code>-less alternative 1: guard flag</a></li> + <li><a href="#goto-less-alternative-2-code-duplication" id="markdown-toc-goto-less-alternative-2-code-duplication"><code>goto</code>-less alternative 2: code duplication</a></li> + </ul> + </li> + <li><a href="#optimizations" id="markdown-toc-optimizations">Optimizations</a></li> + <li><a href="#structured-programming-with-go-to-statements" id="markdown-toc-structured-programming-with-go-to-statements"><em>Structured Programming with <strong>go to</strong> Statements</em></a></li> +</ul> + +<h1 id="errorexception-handling--cleanup">Error/exception handling &amp; cleanup</h1> + +<p>Poster child of using <code>goto</code> – most of the times accepted, often recommended, +sometimes even straight up mandated. This pattern results in a good quality +code, because the operations of the algorithm are <em>structured</em> in a clear order, +while errors and other overhead is handled somewhere else, outside the mainline. +The alternatives make the code less readable as it's hard to spot where the +main code is buried among the error checks.</p> + +<p>From SEI CERT C Coding Standard:</p> + +<blockquote> + <p>Many functions require the allocation of multiple resources. Failing and +returning somewhere in the middle of this function without freeing all of +the allocated resources could produce a memory leak. It is a common error +to forget to free one (or all) of the resources in this manner, so a <code>goto</code> +chain is the simplest and cleanest way to organize exits while preserving +the order of freed resources.</p> +</blockquote> + +<pre><code class="language-c">int* foo(int bar) +{ + int* return_value = NULL; + + if (!do_something(bar)) { + goto error_1; + } + if (!init_stuff(bar)) { + goto error_2; + } + if (!prepare_stuff(bar)) { + goto error_3; + } + return_value = do_the_thing(bar); + +error_3: + cleanup_3(); +error_2: + cleanup_2(); +error_1: + cleanup_1(); + + return return_value; +} +</code></pre> + +<p><strong>Randomly taken real-life <a href="http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/clk/mmp/clk-audio.c#n345">example from Linux kernel</a>:</strong></p> +<pre><code class="language-c">// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MMP Audio Clock Controller driver + * + * Copyright (C) 2020 Lubomir Rintel &lt;lkundrak@v3.sk&gt; + */ + +static int mmp2_audio_clk_probe(struct platform_device *pdev) +{ + struct mmp2_audio_clk *priv; + int ret; + + priv = devm_kzalloc(&amp;pdev-&gt;dev, + struct_size(priv, clk_data.hws, + MMP2_CLK_AUDIO_NR_CLKS), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&amp;priv-&gt;lock); + platform_set_drvdata(pdev, priv); + + priv-&gt;mmio_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv-&gt;mmio_base)) + return PTR_ERR(priv-&gt;mmio_base); + + pm_runtime_enable(&amp;pdev-&gt;dev); + ret = pm_clk_create(&amp;pdev-&gt;dev); + if (ret) + goto disable_pm_runtime; + + ret = pm_clk_add(&amp;pdev-&gt;dev, "audio"); + if (ret) + goto destroy_pm_clk; + + ret = register_clocks(priv, &amp;pdev-&gt;dev); + if (ret) + goto destroy_pm_clk; + + return 0; + +destroy_pm_clk: + pm_clk_destroy(&amp;pdev-&gt;dev); +disable_pm_runtime: + pm_runtime_disable(&amp;pdev-&gt;dev); + + return ret; +} +</code></pre> + +<h2 id="goto-less-alternative-1-nested-ifs"><code>goto</code>-less alternative 1: nested <code>if</code>s</h2> + +<p>Drawbacks:</p> +<ul> + <li>nesting (<em>arrow anti-pattern</em>)</li> + <li>potentially duplicated code (see example function from Linux)</li> +</ul> + +<pre><code class="language-c">int* foo(int bar) +{ + int* return_value = NULL; + + if (do_something(bar)) { + if (init_stuff(bar)) { + if (prepare_stuff(bar)) { + return_value = do_the_thing(bar); + } + cleanup_3(); + } + cleanup_2(); + } + cleanup_1(); + + return return_value; +} +</code></pre> + +<details> +<summary>Example from Linux kernel rewritten</summary> +<div> + <pre><code class="language-c">static int mmp2_audio_clk_probe(struct platform_device *pdev) +{ + // ... + pm_runtime_enable(&amp;pdev-&gt;dev); + + ret = pm_clk_create(&amp;pdev-&gt;dev); + if (!ret) { + ret = pm_clk_add(&amp;pdev-&gt;dev, "audio"); + if (!ret) { + ret = register_clocks(priv, &amp;pdev-&gt;dev); + if (!ret) { + pm_clk_destroy(&amp;pdev-&gt;dev); + pm_runtime_disable(&amp;pdev-&gt;dev); + } + } else { + pm_clk_destroy(&amp;pdev-&gt;dev); + pm_runtime_disable(&amp;pdev-&gt;dev); + } + } else { + pm_runtime_disable(&amp;pdev-&gt;dev); + } + + return ret; // original was returning 0 explicitly +} +</code></pre> + </div> +</details> + +<p><span></span></p> + +<p>And here Microsoft provides us with a <a href="https://learn.microsoft.com/en-us/windows/win32/shell/common-file-dialog#basic-usage">lovely example of such "beautiful" nesting</a> +(<a href="https://web.archive.org/web/20221203064532/https://learn.microsoft.com/en-us/windows/win32/shell/common-file-dialog#basic-usage">archived version</a>).</p> + +<h2 id="goto-less-alternative-2-if-not-then-clean"><code>goto</code>-less alternative 2: if not then clean</h2> + +<p>Drawbacks:</p> +<ul> + <li>duplicated code</li> + <li>multiple exit points</li> +</ul> + +<pre><code class="language-c">int* foo(int bar) +{ + int* return_value = NULL; + + if (!do_something(bar)) { + cleanup_1(); + return return_value; + } + if (!init_stuff(bar)) { + cleanup_2(); + cleanup_1(); + return return_value; + } + if (!prepare_stuff(bar)) { + cleanup_3(); + cleanup_2(); + cleanup_1(); + return return_value; + } + + cleanup_3(); + cleanup_2(); + cleanup_1(); + + return do_the_thing(bar); +} +</code></pre> + +<details> +<summary>Example from Linux kernel rewritten</summary> +<div> + <pre><code class="language-c">static int mmp2_audio_clk_probe(struct platform_device *pdev) +{ + // ... + pm_runtime_enable(&amp;pdev-&gt;dev); + + ret = pm_clk_create(&amp;pdev-&gt;dev); + if (ret) { + pm_runtime_disable(&amp;pdev-&gt;dev); + return ret; + } + + ret = pm_clk_add(&amp;pdev-&gt;dev, "audio"); + if (ret) { + pm_clk_destroy(&amp;pdev-&gt;dev); + pm_runtime_disable(&amp;pdev-&gt;dev); + return ret; + } + + ret = register_clocks(priv, &amp;pdev-&gt;dev); + if (ret) { + pm_clk_destroy(&amp;pdev-&gt;dev); + pm_runtime_disable(&amp;pdev-&gt;dev); + return ret; + } + + return 0; +} +</code></pre> + </div> +</details> + +<h2 id="goto-less-alternative-3-flags"><code>goto</code>-less alternative 3: flags</h2> + +<p>Drawbacks:</p> +<ul> + <li>additional variables</li> + <li>"cascading" booleans</li> + <li>potential nesting</li> + <li>potential complicated boolean expressions</li> +</ul> + +<pre><code class="language-c">int* foo(int bar) +{ + int* return_value = NULL; + + bool flag_1 = false; + bool flag_2 = false; + bool flag_3 = false; + + flag_1 = do_something(bar); + if (flag_1) { + flag_2 = init_stuff(bar); + } + if (flag_2) { + flag_3 = prepare_stuff(bar); + } + if (flag_3) { + return_value = do_the_thing(bar); + } + + if (flag_3) { + cleanup_3(); + } + if (flag_2) { + cleanup_2(); + } + if (flag_1) { + cleanup_1(); + } + + return return_value; +} +</code></pre> + +<aside> + <p>Rewrite of <code>mmp2_audio_clk_probe()</code> function doesn't fit clearly into +this case, thus I've put two variants under alternative 3.5 instead.</p> +</aside> + +<h2 id="goto-less-alternative-35-so-far-ok-flag"><code>goto</code>-less alternative 3.5: so-far-ok flag</h2> + +<pre><code class="language-c">int foo(int bar) +{ + int return_value = 0; + bool something_done = false; + bool stuff_inited = false; + bool stuff_prepared = false; + bool oksofar = true; + + if (oksofar) { // this IF is optional (always execs) but included for consistency + if (do_something(bar)) { + something_done = true; + } else { + oksofar = false; + } + } + + if (oksofar) { + if (init_stuff(bar)) { + stuff_inited = true; + } else { + oksofar = false; + } + } + + if (oksofar) { + if (prepare_stuff(bar)) { + stuff_prepared = true; + } else { + oksofar = false; + } + } + + // Do the thing + if (oksofar) { + return_value = do_the_thing(bar); + } + + // Clean up + if (stuff_prepared) { + cleanup_3(); + } + if (stuff_inited) { + cleanup_2(); + } + if (something_done) { + cleanup_1(); + } + + return return_value; +} +</code></pre> + +<details> +<summary>Example from Linux kernel rewritten</summary> +<div> + <pre><code class="language-c">static int mmp2_audio_clk_probe(struct platform_device *pdev) +{ + // ... + pm_runtime_enable(&amp;pdev-&gt;dev); + + bool destroy_pm_clk = false; + + ret = pm_clk_create(&amp;pdev-&gt;dev); + if (!ret) { + ret = pm_clk_add(&amp;pdev-&gt;dev, "audio"); + if (ret) { + destroy_pm_clk = true; + } + } + if (!ret) { + ret = register_clocks(priv, &amp;pdev-&gt;dev); + if (ret) { + destroy_pm_clk = true; + } + } + + if (ret) { + if (destroy_pm_clk) { + pm_clk_destroy(&amp;pdev-&gt;dev); + } + pm_runtime_disable(&amp;pdev-&gt;dev); + return ret; + } + + return 0; +} +</code></pre> + </div> +</details> +<details> +<summary>Example from Linux kernel rewritten</summary> +<div> + <pre><code class="language-c">static int mmp2_audio_clk_probe(struct platform_device *pdev) +{ + // ... + pm_runtime_enable(&amp;pdev-&gt;dev); + + bool destroy_pm_clk = false; + bool disable_pm_runtime = false; + + ret = pm_clk_create(&amp;pdev-&gt;dev); + if (ret) { + disable_pm_runtime = true; + } + if (!ret) { + ret = pm_clk_add(&amp;pdev-&gt;dev, "audio"); + if (ret) { + destroy_pm_clk = true; + } + } + if (!ret) { + ret = register_clocks(priv, &amp;pdev-&gt;dev); + if (ret) { + destroy_pm_clk = true; + } + } + + if (destroy_pm_clk) { + pm_clk_destroy(&amp;pdev-&gt;dev); + } + if (disable_pm_runtime) { + pm_runtime_disable(&amp;pdev-&gt;dev); + } + + return ret; +} +</code></pre> + </div> +</details> + +<h2 id="goto-less-alternative-4-functions"><code>goto</code>-less alternative 4: functions</h2> + +<p>Drawbacks:</p> +<ul> + <li><span title="Things should not be multiplied beyond what is required">"Entia non sunt multiplicanda praeter necessitatem"</span></li> + <li>reading bottom-up instead of top-bottom</li> + <li>may require passing context around</li> +</ul> + +<pre><code class="language-c">static inline int foo_2(int bar) +{ + int return_value = 0; + if (prepare_stuff(bar)) { + return_value = do_the_thing(bar); + } + cleanup_3(); + return return_value; +} + +static inline int foo_1(int bar) +{ + int return_value = 0; + if (init_stuff(bar)) { + return_value = foo_2(bar); + } + cleanup_2(); + return return_value; +} + +int foo(int bar) +{ + int return_value = 0; + if (do_something(bar)) { + return_value = foo_1(bar); + } + cleanup_1(); + return return_value; +} +</code></pre> + +<details> +<summary>Example from Linux kernel rewritten</summary> +<div> + <pre><code class="language-c">static inline int mmp2_audio_clk_probe_3(struct platform_device* pdev) +{ + int ret = register_clocks(priv, &amp;pdev-&gt;dev); + if (ret) { + pm_clk_destroy(&amp;pdev-&gt;dev); + } + return ret; +} + +static inline int mmp2_audio_clk_probe_2(struct platform_device* pdev) +{ + int ret = pm_clk_add(&amp;pdev-&gt;dev, "audio"); + if (ret) { + pm_clk_destroy(&amp;pdev-&gt;dev); + } else { + ret = mmp2_audio_clk_probe_3(pdev); + } + return ret; +} + +static inline int mmp2_audio_clk_probe_1(struct platform_device* pdev) +{ + int ret = pm_clk_create(&amp;pdev-&gt;dev); + if (ret) { + pm_runtime_disable(&amp;pdev-&gt;dev); + } else { + ret = mmp2_audio_clk_probe_2(pdev); + if (ret) { + pm_runtime_disable(&amp;pdev-&gt;dev); + } + } + return ret; +} + +static int mmp2_audio_clk_probe(struct platform_device* pdev) +{ + // ... + pm_runtime_enable(&amp;pdev-&gt;dev); + + ret = mmp2_audio_clk_probe_1(pdev); + + return ret; +} +</code></pre> + </div> +</details> + +<h2 id="goto-less-alternative-5-abuse-of-loops"><code>goto</code>-less alternative 5: abuse of loops</h2> + +<p>Drawbacks:</p> +<ul> + <li>half of the drawback of <code>goto</code></li> + <li>half of the drawback of other alternatives</li> + <li>none of the benefits of either of the above</li> + <li>not structural anyway</li> + <li>creates loop which doesn't loop</li> + <li>abuse of one language construct just to avoid using the right tool for the job</li> + <li>less readable</li> + <li>counter intuitive, confusing</li> + <li>adds unnecessary nesting</li> + <li>takes more lines</li> + <li>don't even think about using a legitimate loop somewhere among this mess</li> +</ul> + +<pre><code class="language-c">int* foo(int bar) +{ + int* return_value = NULL; + + do { + if (!do_something(bar)) break; + do { + if (!init_stuff(bar)) break; + do { + if (!prepare_stuff(bar)) break; + return_value = do_the_thing(bar); + } while (0); + cleanup_3(); + } while (0); + cleanup_2(); + } while (0); + cleanup_1(); + + return return_value; +} +</code></pre> + +<details> +<summary>Example from Linux kernel rewritten</summary> +<div> + <pre><code class="language-c">static int mmp2_audio_clk_probe(struct platform_device *pdev) +{ + // ... + pm_runtime_enable(&amp;pdev-&gt;dev); + + do { + ret = pm_clk_create(&amp;pdev-&gt;dev); + if (ret) break; + + do { + ret = pm_clk_add(&amp;pdev-&gt;dev, "audio"); + if (ret) break; + + ret = register_clocks(priv, &amp;pdev-&gt;dev); + if (ret) break; + } while (0); + pm_clk_destroy(&amp;pdev-&gt;dev); + } while (0); + pm_runtime_disable(&amp;pdev-&gt;dev); + + return ret; +} +</code></pre> + </div> +</details> + +<h1 id="restartretry">Restart/retry</h1> + +<p>Common especially on *nix systems when dealing with system calls returning +an error after being interrupted by a signal + setting <code>errno</code> to <code>EINTR</code> +to indicate the it was doing fine and was just interrupted. +Of course, it's not limited to system calls.</p> + +<pre><code class="language-c">#include &lt;errno.h&gt; + +int main() +{ +retry_syscall: + if (some_syscall() == -1) { + if (errno == EINTR) { + goto retry_syscall; + } + + // handle real errors + } + + return 0; +} +</code></pre> + +<aside> + <p>I think in this particular case this one level of additional nesting isn't so +bad, but to be fair, without rewriting it I wouldn't be able to fairly present +the <code>goto</code>-less alternative.</p> + + <details> +<summary>Version with reduced nesting</summary> + +<div> + <pre><code class="language-c">#include &lt;errno.h&gt; + +int main() +{ + int res; +retry_syscall: + res = some_syscall(); + if (res == -1 &amp;&amp; errno == EINTR) { + goto retry_syscall; + } + + if (res) { + // handle real errors + } + + return 0; +} +</code></pre> + </div> +</details> +</aside> + +<h2 id="goto-less-alternative-loop"><code>goto</code>-less alternative: loop</h2> + +<p>We can of course use a <code>do {} while</code> loop with conditions in <code>while</code>:</p> + +<pre><code class="language-c">#include &lt;errno.h&gt; + +int main() +{ + int res; + do { + res = some_system_call(); + } while (res == -1 &amp;&amp; errno == EINTR); + + if (res == -1) { + // handle real errors + } + + return 0; +} +</code></pre> + +<p>I think both versions are comparatively readable, but <code>goto</code> has slight advantage +by making it immediately clear the looping is not a desirable situation, while +<code>while</code> loop may be misinterpreted as <a href="https://en.wikipedia.org/wiki/Busy_waiting">waiting loop</a>.</p> + +<h2 id="less-trivial-example">Less trivial example</h2> + +<p>For those, I'm willing to break the overall monochrome theme of the site and +define colors for syntax highlights. Even with simple parsing done by kramdown +(your code editor would certainty do a better job here), we already notice +labels and <code>goto</code> statements standing out a little from the rest of the code. +Flags on the other hand get lost among other variables.</p> + +<style> +.k, .kt { color: #66d9ef; font-weight:bold } +.c1, .cm { color: #75715e } +.cp { color: #75715e; font-weight: bold } +.o { color: #f92672; font-weight: bold } +.mi { color: #ae81ff } +.nf { color: #a6e22e } +.p { color: #f7a000 } +.nl { color: #f4f406 } +</style> + +<h3 id="goto-version"><code>goto</code> version</h3> + +<div> + + <figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="cp">#include &lt;string.h&gt; +</span> +<span class="k">enum</span> <span class="p">{</span> + <span class="n">PKT_THIS_OPERATION</span><span class="p">,</span> + <span class="n">PKT_THAT_OPERATION</span><span class="p">,</span> + <span class="n">PKT_PROCESS_CONDITIONALLY</span><span class="p">,</span> + <span class="n">PKT_CONDITION_SKIPPED</span><span class="p">,</span> + <span class="n">PKT_ERROR</span><span class="p">,</span> + <span class="n">READY_TO_SEND</span><span class="p">,</span> + <span class="n">NOT_READY_TO_SEND</span> +<span class="p">};</span> + +<span class="kt">int</span> <span class="nf">parse_packet</span><span class="p">()</span> +<span class="p">{</span> + <span class="k">static</span> <span class="kt">int</span> <span class="n">packet_error_count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="kt">int</span> <span class="n">packet</span><span class="p">[</span><span class="mi">16</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span> + <span class="kt">int</span> <span class="n">packet_length</span> <span class="o">=</span> <span class="mi">123</span><span class="p">;</span> + <span class="kt">_Bool</span> <span class="n">packet_condition</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">packet_status</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span> + + <span class="c1">// get packet etc. ...</span> + +<span class="nl">REPARSE_PACKET:</span> + <span class="k">switch</span> <span class="p">(</span><span class="n">packet</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="p">{</span> + <span class="k">case</span> <span class="n">PKT_THIS_OPERATION</span><span class="p">:</span> + <span class="k">if</span> <span class="p">(</span><span class="cm">/* problem condition */</span><span class="p">)</span> <span class="p">{</span> + <span class="k">goto</span> <span class="n">PACKET_ERROR</span><span class="p">;</span> + <span class="p">}</span> + <span class="c1">// ... handle THIS_OPERATION</span> + <span class="k">break</span><span class="p">;</span> + + <span class="k">case</span> <span class="n">PKT_THAT_OPERATION</span><span class="p">:</span> + <span class="k">if</span> <span class="p">(</span><span class="cm">/* problem condition */</span><span class="p">)</span> <span class="p">{</span> + <span class="k">goto</span> <span class="n">PACKET_ERROR</span><span class="p">;</span> + <span class="p">}</span> + <span class="c1">// ... handle THAT_OPERATION</span> + <span class="k">break</span><span class="p">;</span> + + <span class="c1">// ...</span> + + <span class="k">case</span> <span class="n">PKT_PROCESS_CONDITIONALLY</span><span class="p">:</span> + <span class="k">if</span> <span class="p">(</span><span class="n">packet_length</span> <span class="o">&lt;</span> <span class="mi">9</span><span class="p">)</span> <span class="p">{</span> + <span class="k">goto</span> <span class="n">PACKET_ERROR</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">if</span> <span class="p">(</span><span class="n">packet_condition</span> <span class="o">&amp;&amp;</span> <span class="n">packet</span><span class="p">[</span><span class="mi">4</span><span class="p">])</span> <span class="p">{</span> + <span class="n">packet_length</span> <span class="o">-=</span> <span class="mi">5</span><span class="p">;</span> + <span class="n">memmove</span><span class="p">(</span><span class="n">packet</span><span class="p">,</span> <span class="n">packet</span><span class="o">+</span><span class="mi">5</span><span class="p">,</span> <span class="n">packet_length</span><span class="p">);</span> + <span class="k">goto</span> <span class="n">REPARSE_PACKET</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> + <span class="n">packet</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">PKT_CONDITION_SKIPPED</span><span class="p">;</span> + <span class="n">packet</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="n">packet_length</span><span class="p">;</span> + <span class="n">packet_length</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span> + <span class="n">packet_status</span> <span class="o">=</span> <span class="n">READY_TO_SEND</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">break</span><span class="p">;</span> + + <span class="c1">// ...</span> + + <span class="nl">default:</span> +<span class="nl">PACKET_ERROR:</span> + <span class="n">packet_error_count</span><span class="o">++</span><span class="p">;</span> + <span class="n">packet_length</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span> + <span class="n">packet</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">PKT_ERROR</span><span class="p">;</span> + <span class="n">packet_status</span> <span class="o">=</span> <span class="n">READY_TO_SEND</span><span class="p">;</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> + + <span class="c1">// ...</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +</div> + +<h3 id="goto-less-version"><code>goto</code>-less version</h3> +<div> + + <figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="cp">#include &lt;string.h&gt; +</span> +<span class="k">enum</span> <span class="p">{</span> + <span class="n">PKT_THIS_OPERATION</span><span class="p">,</span> + <span class="n">PKT_THAT_OPERATION</span><span class="p">,</span> + <span class="n">PKT_PROCESS_CONDITIONALLY</span><span class="p">,</span> + <span class="n">PKT_CONDITION_SKIPPED</span><span class="p">,</span> + <span class="n">PKT_ERROR</span><span class="p">,</span> + <span class="n">READY_TO_SEND</span><span class="p">,</span> + <span class="n">NOT_READY_TO_SEND</span> +<span class="p">};</span> + +<span class="kt">int</span> <span class="nf">parse_packet</span><span class="p">()</span> +<span class="p">{</span> + <span class="k">static</span> <span class="kt">int</span> <span class="n">packet_error_count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> + + <span class="kt">int</span> <span class="n">packet</span><span class="p">[</span><span class="mi">16</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span> + <span class="kt">int</span> <span class="n">packet_length</span> <span class="o">=</span> <span class="mi">123</span><span class="p">;</span> + <span class="kt">_Bool</span> <span class="n">packet_condition</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> + <span class="kt">int</span> <span class="n">packet_status</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span> + + <span class="c1">// get packet etc. ...</span> + + <span class="kt">_Bool</span> <span class="n">REPARSE_PACKET</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> + <span class="kt">_Bool</span> <span class="n">PACKET_ERROR</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span> + + <span class="k">while</span> <span class="p">(</span><span class="n">REPARSE_PACKET</span><span class="p">)</span> <span class="p">{</span> + <span class="n">REPARSE_PACKET</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span> + <span class="n">PACKET_ERROR</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span> + + <span class="k">switch</span> <span class="p">(</span><span class="n">packet</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="p">{</span> + <span class="k">case</span> <span class="n">PKT_THIS_OPERATION</span><span class="p">:</span> + <span class="k">if</span> <span class="p">(</span><span class="cm">/* problem condition */</span><span class="p">)</span> <span class="p">{</span> + <span class="n">PACKET_ERROR</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> + <span class="c1">// ... handle THIS_OPERATION</span> + <span class="k">break</span><span class="p">;</span> + + <span class="k">case</span> <span class="n">PKT_THAT_OPERATION</span><span class="p">:</span> + <span class="k">if</span> <span class="p">(</span><span class="cm">/* problem condition */</span><span class="p">)</span> <span class="p">{</span> + <span class="n">PACKET_ERROR</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> + <span class="c1">// ... handle THAT_OPERATION</span> + <span class="k">break</span><span class="p">;</span> + + <span class="c1">// ...</span> + + <span class="k">case</span> <span class="n">PKT_PROCESS_CONDITIONALLY</span><span class="p">:</span> + <span class="k">if</span> <span class="p">(</span><span class="n">packet_length</span> <span class="o">&lt;</span> <span class="mi">9</span><span class="p">)</span> <span class="p">{</span> + <span class="n">PACKET_ERROR</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">if</span> <span class="p">(</span><span class="n">packet_condition</span> <span class="o">&amp;&amp;</span> <span class="n">packet</span><span class="p">[</span><span class="mi">4</span><span class="p">])</span> <span class="p">{</span> + <span class="n">packet_length</span> <span class="o">-=</span> <span class="mi">5</span><span class="p">;</span> + <span class="n">memmove</span><span class="p">(</span><span class="n">packet</span><span class="p">,</span> <span class="n">packet</span><span class="o">+</span><span class="mi">5</span><span class="p">,</span> <span class="n">packet_length</span><span class="p">);</span> + <span class="n">REPARSE_PACKET</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> + <span class="n">packet</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">PKT_CONDITION_SKIPPED</span><span class="p">;</span> + <span class="n">packet</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="n">packet_length</span><span class="p">;</span> + <span class="n">packet_length</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span> + <span class="n">packet_status</span> <span class="o">=</span> <span class="n">READY_TO_SEND</span><span class="p">;</span> + <span class="p">}</span> + <span class="k">break</span><span class="p">;</span> + + <span class="c1">// ...</span> + + <span class="nl">default:</span> + <span class="n">PACKET_ERROR</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">if</span> <span class="p">(</span><span class="n">PACKET_ERROR</span><span class="p">)</span> <span class="p">{</span> + <span class="n">packet_error_count</span><span class="o">++</span><span class="p">;</span> + <span class="n">packet_length</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span> + <span class="n">packet</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">PKT_ERROR</span><span class="p">;</span> + <span class="n">packet_status</span> <span class="o">=</span> <span class="n">NOT_READY_TO_SEND</span><span class="p">;</span> + <span class="k">break</span><span class="p">;</span> + <span class="p">}</span> + <span class="p">}</span> + + <span class="c1">// ...</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span></code></pre></figure> + +</div> + +<h1 id="common-code-in-switch-statement">Common code in <code>switch</code> statement</h1> + +<p>This situation may be a good opportunity to check if the code doesn't need to +be refactored altogether; that being said, sometimes you want to have <code>switch</code> +statement where cases make minor changes then run the same code.</p> + +<p>Sure, you could extract the common code into function, but then you need to pass +all the context to it, but that may be inconvenient (for you may need to pass +a lot of parameters or making a dedicated structure, in both cases probably with +pointers) and may increase complexity of the code; in some cases, you may wish +there being only one call to the function instead of multiple.</p> + +<p>So why not just jump to the common code?</p> + +<pre><code class="language-c">int foo(int v) +{ + // ... + int something = 0; + switch (v) { + case FIRST_CASE: + something = 2; + goto common1; + case SECOND_CASE: + something = 7; + goto common1; + case THIRD_CASE: + something = 9; + goto common1; +common1: + /* code common to FIRST, SECOND and THIRD cases */ + break; + + case FOURTH_CASE: + something = 10; + goto common2; + case FIFTH_CASE: + something = 42; + goto common2; +common2: + /* code common to FOURTH and FIFTH cases */ + break; + } + // ... +} +</code></pre> + +<h2 id="goto-less-alternative-1-functions"><code>goto</code>-less alternative 1: functions</h2> + +<p>Drawbacks:</p> +<ul> + <li><span title="Things should not be multiplied beyond what is required">"Entia non sunt multiplicanda praeter necessitatem"</span></li> + <li>reading bottom-up instead of top-bottom</li> + <li>may require passing context around</li> +</ul> + +<pre><code class="language-c">struct foo_context { + int* something; + // ... +}; + +static void common1(struct foo_context ctx) +{ + /* code common to FIRST, SECOND and THIRD cases */ +} + +static void common2(struct foo_context ctx) +{ + /* code common to FOURTH and FIFTH cases */ +} + +int foo(int v) +{ + struct foo_context ctx = { NULL }; + // ... + int something = 0; + ctx.something = &amp;something; + + switch (v) { + case FIRST_CASE: + something = 2; + common1(ctx); + break; + case SECOND_CASE: + something = 7; + common1(ctx); + break; + case THIRD_CASE: + something = 9; + common1(ctx); + break; + + case FOURTH_CASE: + something = 10; + common2(ctx); + break; + case FIFTH_CASE: + something = 42; + common2(ctx); + break; + } + // ... +} +</code></pre> + +<h2 id="goto-less-alternative-2-ifs"><code>goto</code>-less alternative 2: <code>if</code>s</h2> + +<p>We can abandon elegance and replace the <code>switch</code> statement with <code>if</code>s</p> + +<pre><code class="language-c">int foo(int v) +{ + // ... + int something = 0; + if (v == FIRST_CASE || v == SECOND_CASE || v == THIRD_CASE) { + if (v == FIRST_CASE) { + something = 2; + } else if (v == SECOND_CASE) { + something = 7; + } else if (v == THIRD_CASE) { // it could be just `else` + something = 9; + } + /* code common to FIRST, SECOND and THIRD cases */ + } else if (v == FOURTH_CASE || v == FIFTH_CASE) { + if (v == FOURTH_CASE) { + something = 10; + } else { + something = 42; + } + /* code common to FOURTH and FIFTH cases */ + } + // ... +} +</code></pre> + +<h2 id="goto-less-alternative-3-interlacing-if-0"><code>goto</code>-less alternative 3: interlacing <code>if (0)</code></h2> + +<p>Please, don't, just don't…</p> + +<pre><code class="language-c">int foo(int v) +{ + // ... + int something = 0; + switch (v) { + case FIRST_CASE: + something = 2; + if (0) { + case SECOND_CASE: + something = 7; + } + if (0) { + case THIRD_CASE: + something = 9; + } + /* code common to FIRST, SECOND and THIRD cases */ + break; + + case FOURTH_CASE: + something = 10; + if (0) { + case FIFTH_CASE: + something = 42; + } + /* code common to FOURTH and FIFTH cases */ + break; + } + // ... +} +</code></pre> + +<h2 id="goto-less-alternative-capturing-lambda"><del><code>goto</code>-less alternative: capturing lambda</del></h2> + +<p>Yeah, maybe some day…</p> + +<h1 id="nested-break-labeled-continue">Nested <code>break</code>, labeled <code>continue</code></h1> + +<p>I think this one doesn't require further explanation:</p> + +<pre><code class="language-c">#include &lt;stdio.h&gt; + +int main() +{ + for (int i = 1; i &lt;= 5; ++i) { + printf("outer iteration (i): %d\n", i); + + for (int j = 1; j &lt;= 200; ++j) { + printf(" inner iteration (j): %d\n", j); + if (j &gt;= 3) { + break; // breaks from inner loop, outer loop continues + } + if (i &gt;= 2) { + goto outer; // breaks from outer loop, and directly to "Done!" + } + } + } +outer: + + puts("Done!"); + + return 0; +} +</code></pre> + +<p>We can use <a href="https://beej.us/guide/bgc/html/split/goto.html#labeled-continue">analogous mechanism for <code>continue</code></a>.</p> + +<p> </p> + +<p><em>Beej's Guide to C Programming</em> has nice example of using this technique alongside the cleanup one:</p> + +<blockquote> + <pre><code class="language-c"> for (...) { + for (...) { + while (...) { + do { + if (some_error_condition) { + goto bail; + } + // ... + } while(...); + } + } + } + +bail: + // Cleanup here +</code></pre> + + <p>Without <code>goto</code>, you’d have to check an error condition +flag in all of the loops to get all the way out.</p> +</blockquote> + +<h1 id="simple-state-machines">Simple state machines</h1> + +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 260 130" style="font-family: Times"> + <g fill="#ffffff" stroke="#ffffff"> + <ellipse cx="80" cy="100" rx="10" ry="10" /> + <ellipse cx="160" cy="101" rx="10" ry="10" /> + <ellipse cx="120" cy="41" rx="10" ry="10" /> + </g> + + <g fill="black"> + <text x="73" y="106">A</text> + <text x="154" y="107">B</text> + <text x="113" y="47">C</text> + </g> + + <g fill="white"> + <g stroke="white"> + <path d="M 80 91 L 80 51 Q 80 41 90 41 L 105.88 41" fill="none" /> + <path d="M 108.88 41 L 104.88 43 L 105.88 41 L 104.88 39 Z" /> + + <path d="M 130 41 L 150 41 Q 160 41 160 51 L 160 86.88" fill="none" /> + <path d="M 160 89.88 L 158 85.88 L 160 86.88 L 162 85.88 Z" /> + + <path d="M 152.93 108.07 Q 140 121 120 121 Q 100 121 89.98 110.98" fill="none" /> + <path d="M 87.86 108.86 L 92.1 110.28 L 89.98 110.98 L 89.28 113.1 Z" /> + + <path d="M 87.07 93.93 Q 100 81 120 81 Q 140 81 150.02 91.02" fill="none" /> + <path d="M 152.14 93.14 L 147.9 91.72 L 150.02 91.02 L 150.72 88.9 Z" /> + + <path d="M 112.93 33.93 Q 113 11 120 11 Q 127 11 127.06 29.81" fill="none" /> + <path d="M 127.00 32.81 L 125.06 28.82 L 127.06 29.81 L 129.06 28.8 Z" /> + + <path d="M 80 111 Q 80 131 70 126 Q 60 121 70.02 110.98" fill="none" /> + <path d="M 72.14 108.86 L 70.72 113.1 L 70.02 110.98 L 67.9 110.28 Z" /> + + <path d="M 160 111 Q 160 131 170 126 Q 180 121 169.98 110.98" fill="none" /> + <path d="M 167.86 108.86 L 172.1 110.28 L 169.98 110.98 L 169.28 113.1 Z" /> + + <path d="M 30 91 L 66 100" fill="none" /> + <path d="M 68.92 100.73 L 64.55 101.7 L 66 100 L 65.52 97.82 Z" /> + + <path d="M 170 101 L 206 92" fill="none" /> + <path d="M 208.92 91.27 L 205.52 94.18 L 206 92 L 204.55 90.3 Z" /> + </g> + + <text x="16" y="90">S</text> + <text x="214" y="90">F</text> + + <g font-size="0.7em"> + <text x="117" y="7">x</text> + + <text x="70" y="55">y</text> + <text x="165" y="55">z</text> + + <text x="117" y="75">x</text> + <text x="117" y="115">y</text> + + <text x="55" y="125">z</text> + <text x="180" y="125">x</text> + + <text x="180" y="90" font-style="italic">nul</text> + </g> + </g> +</svg> + +<p>The following is a 1:1, not far from <strong>verbatim mathematical notation</strong>, +implementation of the above state machine:</p> + +<pre><code class="language-c">_Bool machine(const char* c) +{ +qA: + switch (*(c++)) { + case 'x': goto qB; + case 'y': goto qC; + case 'z': goto qA; + default: goto err; + } + +qB: + switch (*(c++)) { + case 'x': goto qC; + case 'z': goto qB; + case '\0': goto F; + default: goto err; + } + +qC: + switch (*(c++)) { + case 'x': goto qB; + case 'y': goto qA; + default: goto err; + } + +F: + return true; + +err: + return false; +} +</code></pre> + +<h1 id="jumping-into-event-loop">Jumping into event loop</h1> + +<p>Yeah, yeah, I know jumping <em>into</em> warrants at least a raised eyebrow. +That being said, there are cases when you may want to do just that.</p> + +<p>Here in first iteration program skips increasing variable and goes straight +to allocation. Each following iteration executes code as written, ignoring +completely the label relevant only for the first run; so you do too during +analysis.</p> + +<pre><code class="language-c">#include &lt;stdio.h&gt; +#include &lt;fancy_alloc.h&gt; + +int main() +{ + int* buf = NULL; + size_t pos = 0; + size_t sz = 8; + + int* temp; + + goto ALLOC; + do { + if (pos &gt; sz) { // resize array + sz *= 2; +ALLOC: temp = arrayAllocSmart(buf, sz, pos); + /* check for errors */ + buf = temp; + } + + /* do something with buf */ + } while (checkQuit()); + + return 0; + + /* handle errors ... */ +} +</code></pre> + +<h3 id="goto-less-alternative-1-guard-flag"><code>goto</code>-less alternative 1: guard flag</h3> + +<p>I probably says more about the state of my sleep deprived brain than anything +else, but I actually managed to make an honest, very dumb mistake in this +simple snippet. I didn't notice until after examining the assembly output +and seeing way less instructions than expected. Since it's simple, yet quite +severe in consequences, I decided to leave it as an exercise for the reader +to spot the bug (should be easy since you already know about its existence).</p> + +<p>The drawbacks as per usual: nesting and keeping track of flags.</p> + +<pre><code class="language-c">#include &lt;stdio.h&gt; +#include &lt;fancy_alloc.h&gt; + +int main() +{ + int* buf = NULL; + size_t pos = 0; + size_t sz = 8; + + int ret = 0 + + _Bool firstIter = true; + + do { + if (pos &gt; sz || firstIter) { // resize array + if (!firstIter) { + sz *= 2; + firstIter = false; + } + + int* temp = arrayAllocSmart(buf, sz, pos); + /* handle errors ... */ + buf = temp; + } + + /* do something with buf */ + } while (checkQuit()); + + return 0; +} +</code></pre> + +<h3 id="goto-less-alternative-2-code-duplication"><code>goto</code>-less alternative 2: code duplication</h3> + +<p>The drawback is obvious, thus no further comment.</p> + +<pre><code class="language-c">#include &lt;stdio.h&gt; +#include &lt;fancy_alloc.h&gt; + +int main() +{ + size_t pos = 0; + size_t sz = 8; + + int* buf = arrayAllocSmart(NULL, sz, pos); + /* handle errors ... */ + + do { + if (pos &gt; sz) { // resize array + sz *= 2; + int* temp = arrayAllocSmart(buf, sz, pos); + /* handle errors ... */ + buf = temp; + } + + /* do something with buf */ + } while (checkQuit()); + + return 0; +} +</code></pre> + +<h1 id="optimizations">Optimizations</h1> + +<aside> + <p>This section is purely informative, just to appear on list as to mark the +existence of such use-case. Giving an example for this is not so easy as +most of them apply only in very narrow situations, not rarely bordering +on micro-optimizing.</p> +</aside> + +<aside> + <p>Often extensions like <a href="https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html">computed <code>goto</code></a> are used</p> +</aside> + +<aside> + <p>Beej shows <a href="https://beej.us/guide/bgc/html/split/goto.html#tail-call-optimization">tail call optimization</a> +as an example in his book, unfortunately (from educational standpoint! otherwise very good) modern compilers +easily optimize something as simple as factorial to the very same assembly which we get using the <code>goto</code> +optimization. On the other hand, not everybody is blessed with modern, optimizing compiler…</p> +</aside> + +<h1 id="structured-programming-with-go-to-statements"><a href="https://dl.acm.org/doi/epdf/10.1145/356635.356640"><em>Structured Programming with <strong>go to</strong> Statements</em></a></h1> + +<p>Read at: +  <a href="https://dl.acm.org/doi/epdf/10.1145/356635.356640">[ACM Digital Library]</a> +  <a href="https://pic.plover.com/knuth-GOTO.pdf">[PDF]</a> +  <a href="http://www.kohala.com/start/papers.others/knuth.dec74.html">[HTML]</a></p> + +<p>If I started from Dijkstra, it's only natural I need to conclude with Knuth. <br /> +Almost anybody who says anything positive about <code>goto</code> refers to this paper. +And rightfully so! To this day it's one of most comprehensive resources +on the topic (it's a go to resource about <code>goto</code>). Perhaps some examples +are quite dated, some concerns less crucial today than back in the days, +but nevertheless it's an excellent read.</p> + +<blockquote> + <p>One thing we haven't spelled out clearly, however, is what makes some +<strong>go to</strong>'s bad and others acceptable. The reason is that we've really +been directing our attention to the wrong issue, to the objective question of +<strong>go to</strong> elimination instead of the important subjective question of +program structure. In the words of John Brown, "The act of focusing our +mightiest intellectual resources on the elusive goal of <strong>go to</strong>-less +programs has helped us get our minds off all those really tough and possibly +unresolvable problems and issues with which today's professional programmer +would otherwise have to grapple." By writing this long article I don't want +to add fuel to the controversy about go to elimination, since that topic +has already assumed entirely too much significance; my goal is to lay that +controversy to rest, and to help direct the discussion towards more fruitful +channels.</p> +</blockquote>Jorengarenargotophobia – fear of goto statement, usually caused by misunderstanding and lack of context of stories from dark ages of programming. Programmers with gotophobia tend to make their code less readable just to avoid using goto.Few lesser known tricks, quirks and features of C2023-02-19T00:00:00+00:002023-02-19T00:00:00+00:00https://blog.joren.ga/less-known-c<p>There are some tricks, quirks and features (some quite fundamental to the language!) +which seems to throw even experienced developers off the track. Thus I did a sloppy +job of gathering some of them in this post (in no particular order) with even sloppier +short explanations and/or examples (or quote of thereof).</p> + +<aside> + <ul> + <li><a href="https://stackoverflow.com/q/132241/10247460">Hidden features of C - Stack Overflow</a></li> + <li><a href="https://d3s.mff.cuni.cz/legacy/~holub/c_features.html">Lesser known C features</a></li> + <li><a href="https://news.ycombinator.com/item?id=33680239">Mildly interesting quirks of C | Hacker News</a></li> + <li><a href="https://www.youtube.com/watch?v=w3_e9vZj7D8">Advanced C: The UB and optimizations that trick good programmers.</a></li> + <li><a href="https://www.reddit.com/r/C_Programming/comments/mqk338/interesting_ways_to_use_c/">Interesting ways to use C? : r/C_Programming</a></li> + <li><a href="http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf">C99 with Technical corrigenda TC1, TC2, and TC3 included</a></li> + <li><a href="http://www.robertgamble.net/2011/05/how-well-do-you-know-c.html">Rob's Programming Blog: How Well Do You Know C?</a></li> + <li><a href="https://gist.github.com/shakna-israel/4fd31ee469274aa49f8f9793c3e71163#lets-destroy-c">Let's Destroy C</a></li> + <li><a href="https://jadlevesque.github.io/PPMP-Iceberg/">The Preprocessor Iceberg Meme</a></li> + </ul> +</aside> + +<aside> + <p><strong>WARNING:</strong> Something being listed here does <span style="color:yellow"><strong><em>not</em></strong></span> automatically mean encouragement to use it!</p> +</aside> + +<ul id="markdown-toc"> + <li><a href="#array-pointers" id="markdown-toc-array-pointers">Array pointers</a></li> + <li><a href="#comma-operator" id="markdown-toc-comma-operator">Comma operator</a></li> + <li><a href="#digraphs-trigraphs-and-alternative-tokens" id="markdown-toc-digraphs-trigraphs-and-alternative-tokens">Digraphs, trigraphs and alternative tokens</a></li> + <li><a href="#designated-initializer" id="markdown-toc-designated-initializer">Designated initializer</a></li> + <li><a href="#compound-literals" id="markdown-toc-compound-literals">Compound literals</a></li> + <li><a href="#compound-literals-are-lvalues" id="markdown-toc-compound-literals-are-lvalues">Compound literals are lvalues</a></li> + <li><a href="#multi-character-constants" id="markdown-toc-multi-character-constants">Multi-character constants</a></li> + <li><a href="#bit-fields" id="markdown-toc-bit-fields">Bit fields</a></li> + <li><a href="#0-bit-fields" id="markdown-toc-0-bit-fields">0 bit fields</a></li> + <li><a href="#volatile-type-qualifier" id="markdown-toc-volatile-type-qualifier"><code>volatile</code> type qualifier</a></li> + <li><a href="#restrict-type-qualifier" id="markdown-toc-restrict-type-qualifier"><code>restrict</code> type qualifier</a></li> + <li><a href="#register-type-qualifier" id="markdown-toc-register-type-qualifier"><code>register</code> type qualifier</a></li> + <li><a href="#flexible-array-member" id="markdown-toc-flexible-array-member">Flexible array member</a></li> + <li><a href="#n-format-specifier" id="markdown-toc-n-format-specifier"><code>%n</code> format specifier</a></li> + <li><a href="#-minimum-field-width-format-specifier" id="markdown-toc--minimum-field-width-format-specifier"><code>%.*</code> (minimum field width) format specifier</a></li> + <li><a href="#other-less-known-format-specifiers" id="markdown-toc-other-less-known-format-specifiers">Other less known format specifiers</a></li> + <li><a href="#interlacing-syntactic-constructs" id="markdown-toc-interlacing-syntactic-constructs">Interlacing syntactic constructs</a></li> + <li><a href="#---operator" id="markdown-toc----operator"><code>--&gt;</code> "operator"</a></li> + <li><a href="#idxarr" id="markdown-toc-idxarr"><code>idx[arr]</code></a></li> + <li><a href="#negative-array-indexes" id="markdown-toc-negative-array-indexes">Negative array indexes</a></li> + <li><a href="#constant-string-concatenation" id="markdown-toc-constant-string-concatenation">Constant string concatenation</a></li> + <li><a href="#using--and--as-conditionals" id="markdown-toc-using--and--as-conditionals">Using <code>&amp;&amp;</code> and <code>||</code> as conditionals</a></li> + <li><a href="#compile-time-assumption-checking-using-enums" id="markdown-toc-compile-time-assumption-checking-using-enums">Compile time assumption checking using <code>enum</code>s</a></li> + <li><a href="#ad-hoc-struct-declaration-in-the-return-type-of-a-function" id="markdown-toc-ad-hoc-struct-declaration-in-the-return-type-of-a-function">Ad hoc <code>struct</code> declaration in the return type of a function</a></li> + <li><a href="#nested-struct-definition-is-not-kept-nested" id="markdown-toc-nested-struct-definition-is-not-kept-nested">"Nested" <code>struct</code> definition is not kept nested</a></li> + <li><a href="#flat-initializer-lists" id="markdown-toc-flat-initializer-lists">Flat initializer lists</a></li> + <li><a href="#static-array-indices-in-function-parameter-declarations" id="markdown-toc-static-array-indices-in-function-parameter-declarations">Static array indices in function parameter declarations</a></li> + <li><a href="#macro-overloading-by-argument-list-length" id="markdown-toc-macro-overloading-by-argument-list-length">Macro Overloading by Argument List Length</a></li> + <li><a href="#function-types" id="markdown-toc-function-types">Function types</a></li> + <li><a href="#x-macros" id="markdown-toc-x-macros">X-Macros</a></li> + <li><a href="#named-function-parameters" id="markdown-toc-named-function-parameters">Named function parameters</a></li> + <li><a href="#combining-default-named-and-positional-arguments" id="markdown-toc-combining-default-named-and-positional-arguments">Combining default, named and positional arguments</a></li> + <li><a href="#abusing-unions-for-grouping-things-into-namespaces" id="markdown-toc-abusing-unions-for-grouping-things-into-namespaces">Abusing unions for grouping things into namespaces</a></li> + <li><a href="#matching-character-classes-with-sscanf" id="markdown-toc-matching-character-classes-with-sscanf">Matching character classes with <code>sscanf()</code></a></li> + <li><a href="#garbage-collector" id="markdown-toc-garbage-collector">Garbage collector</a></li> + <li><a href="#cosmopolitan-libc" id="markdown-toc-cosmopolitan-libc">Cosmopolitan Libc</a></li> + <li><a href="#inline-assembly" id="markdown-toc-inline-assembly">Inline assembly</a></li> + <li><a href="#object-oriented-programming" id="markdown-toc-object-oriented-programming">Object Oriented Programming</a></li> + <li><a href="#metaprogramming" id="markdown-toc-metaprogramming">Metaprogramming</a></li> + <li><a href="#evaluate-sizeof-at-compile-time-by-causing-duplicate-case-error" id="markdown-toc-evaluate-sizeof-at-compile-time-by-causing-duplicate-case-error">Evaluate <code>sizeof</code> at compile time by causing duplicate case error</a></li> +</ul> + +<h2 id="array-pointers">Array pointers</h2> + +<p>Decay-to-pointer makes regular pointers to array usually not needed:</p> +<pre><code class="language-c">int arr[10]; + +int* ap0 = arr; // array decay-to-pointer +// ap0[2] = ... + +int (*ap1)[10] = &amp;arr; // proper pointer to array +// (*ap1)[2] = ... +</code></pre> + +<p>But ability to allocate a big multi-dimensional array on heap is nice:</p> +<pre><code class="language-c">int (*ap3)[90000][90000] = malloc(sizeof *ap3); +</code></pre> + +<p>With pointers even VLA can find its use (<a href="https://blog.joren.ga/vla-usecases">more here</a>):</p> +<pre><code class="language-c">int (*ap4)[n] = malloc(sizeof *ap4); +</code></pre> + +<h2 id="comma-operator">Comma operator</h2> + +<p>The comma operator is used to separate two or more expressions that are +included where only one expression is expected. When the set of expressions +has to be evaluated for a value, only the right-most expression is considered.</p> + +<p>For example: <code>b = (a=3, a+2);</code> – this code would firstly assign value 3 +to <code>a</code>, and then <code>a+2</code> would be assigned to variable <code>b</code>. So, at the end, +<code>b</code> would contain value 5 while variable <code>a</code> would be 3.</p> + +<p>On Wikipedia we can find <a href="https://en.wikipedia.org/wiki/Comma_operator#Examples">few more examples</a>:</p> + +<h2 id="digraphs-trigraphs-and-alternative-tokens">Digraphs, trigraphs and alternative tokens</h2> + +<p>C code may not be portable, but the language itself is probably more portable +than any other; there are system using e.g. EBCDIC encoding instead of ASCII, +to support them C has digraphs and trigraphs – multi-character sequences +treated by the compiler as other characters.</p> + +<table> + <thead> + <tr> + <th style="text-align: center">Digraph</th> + <th style="text-align: center"> </th> + <th> </th> + <th style="text-align: center">Trigraph</th> + <th style="text-align: center"> </th> + <th> </th> + <th style="text-align: center">iso646.h</th> + <th style="text-align: center"> </th> + </tr> + </thead> + <tbody> + <tr> + <td style="text-align: center"><code>&lt;:</code></td> + <td style="text-align: center"><code>[</code></td> + <td> </td> + <td style="text-align: center"><code>??=</code></td> + <td style="text-align: center"><code>#</code></td> + <td> </td> + <td style="text-align: center"><code>and</code></td> + <td style="text-align: center"><code>&amp;&amp;</code></td> + </tr> + <tr> + <td style="text-align: center"><code>:&gt;</code></td> + <td style="text-align: center"><code>]</code></td> + <td> </td> + <td style="text-align: center"><code>??(</code></td> + <td style="text-align: center"><code>[</code></td> + <td> </td> + <td style="text-align: center"><code>and_eq</code></td> + <td style="text-align: center"><code>&amp;=</code></td> + </tr> + <tr> + <td style="text-align: center"><code>&lt;%</code></td> + <td style="text-align: center"><code>{</code></td> + <td> </td> + <td style="text-align: center"><code>??/</code></td> + <td style="text-align: center"><code>\</code></td> + <td> </td> + <td style="text-align: center"><code>bitand</code></td> + <td style="text-align: center"><code>&amp;</code></td> + </tr> + <tr> + <td style="text-align: center"><code>%&gt;</code></td> + <td style="text-align: center"><code>}</code></td> + <td> </td> + <td style="text-align: center"><code>??)</code></td> + <td style="text-align: center"><code>]</code></td> + <td> </td> + <td style="text-align: center"><code>bitor</code></td> + <td style="text-align: center"><code>|</code></td> + </tr> + <tr> + <td style="text-align: center"><code>%:</code></td> + <td style="text-align: center"><code>#</code></td> + <td> </td> + <td style="text-align: center"><code>??'</code></td> + <td style="text-align: center"><code>^</code></td> + <td> </td> + <td style="text-align: center"><code>compl</code></td> + <td style="text-align: center"><code>~</code></td> + </tr> + <tr> + <td style="text-align: center"><code>%:%:</code></td> + <td style="text-align: center"><code>##</code></td> + <td> </td> + <td style="text-align: center"><code>??&lt;</code></td> + <td style="text-align: center"><code>{</code></td> + <td> </td> + <td style="text-align: center"><code>not</code></td> + <td style="text-align: center"><code>!</code></td> + </tr> + <tr> + <td style="text-align: center">——–</td> + <td style="text-align: center">———–</td> + <td> </td> + <td style="text-align: center"><code>??!</code></td> + <td style="text-align: center"><code>|</code></td> + <td> </td> + <td style="text-align: center"><code>not_eq</code></td> + <td style="text-align: center"><code>!=</code></td> + </tr> + <tr> + <td style="text-align: center">——–</td> + <td style="text-align: center">———–</td> + <td> </td> + <td style="text-align: center"><code>??&gt;</code></td> + <td style="text-align: center"><code>}</code></td> + <td> </td> + <td style="text-align: center"><code>or</code></td> + <td style="text-align: center"><code>||</code></td> + </tr> + <tr> + <td style="text-align: center">——–</td> + <td style="text-align: center">———–</td> + <td> </td> + <td style="text-align: center"><code>??-</code></td> + <td style="text-align: center"><code>~</code></td> + <td> </td> + <td style="text-align: center"><code>or_eq</code></td> + <td style="text-align: center"><code>|=</code></td> + </tr> + <tr> + <td style="text-align: center">——–</td> + <td style="text-align: center">———–</td> + <td> </td> + <td style="text-align: center">——–</td> + <td style="text-align: center">———–</td> + <td> </td> + <td style="text-align: center"><code>xor</code></td> + <td style="text-align: center"><code>^</code></td> + </tr> + <tr> + <td style="text-align: center">——–</td> + <td style="text-align: center">———–</td> + <td> </td> + <td style="text-align: center">——–</td> + <td style="text-align: center">———–</td> + <td> </td> + <td style="text-align: center"><code>xor_eq</code></td> + <td style="text-align: center"><code>^=</code></td> + </tr> + </tbody> +</table> + +<aside> + <p>Despite there being small opposition, the C Standard Committee +decided to remove support for trigraphs from C23.</p> +</aside> + +<ul> + <li><a href="https://blog.yossarian.net/2015/04/02/Digraphs-And-Trigraphs">Mini-post: Digraphs and Trigraphs | ENOSUCHBLOG</a></li> + <li><a href="https://en.wikipedia.org/wiki/C_alternative_tokens">C alternative tokens - Wikipedia</a></li> + <li><a href="https://stackoverflow.com/q/432443/10247460">Why are there digraphs in C and C++? - Stack Overflow</a></li> + <li><a href="https://stackoverflow.com/q/1234582/10247460">Purpose of Trigraph sequences in C++?</a></li> +</ul> + +<h2 id="designated-initializer">Designated initializer</h2> + +<p>These allow you to specify which elements of an object (array, structure, union) +are to be initialized by the values following. The order does not matter!</p> + +<pre><code class="language-c">struct Foo { + int x, y; + const char* bar; +}; + +void f(void) +{ + int arr[] = { 1, 2, [5] = 9, [9] = 5, [8] = 8 }; + + struct Foo f = { .y = 23, .bar = "barman", .x = -38 }; + + struct Foo arr[] = { + [10] = { 8, 8, 9 }, + [8] = { 1, 8, bar3 }, + [12] = { .x = 9, .z = 8 }, + }; +} +</code></pre> + +<ul> + <li><a href="https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html">Designated Inits (Using the GNU Compiler Collection (GCC))</a></li> + <li><a href="https://www.ibm.com/docs/en/zos/2.5.0?topic=initializers-designated-aggregate-types-c-only">Designated initializers for aggregate types (C only) - IBM Documentation</a></li> + <li><a href="https://stackoverflow.com/q/47202557/10247460">What is a designated initializer in C? - Stack Overflow</a></li> +</ul> + +<h2 id="compound-literals">Compound literals</h2> + +<p>A compound literal looks like a cast of a brace-enclosed initializer list. +Its value is an object of the type specified in the cast, containing the +elements specified in the initializer.</p> + +<pre><code class="language-c">#include &lt;stdio.h&gt; + +struct Foo { int x, y; }; + +void bar(struct Foo p) +{ + printf("%d, %d", p.x, p.y); +} + +int main(void) +{ + bar((struct Foo){2, 3}); + return 0; +} +</code></pre> + +<ul> + <li><a href="https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html">Compound Literals (Using the GNU Compiler Collection (GCC))</a></li> +</ul> + +<h2 id="compound-literals-are-lvalues">Compound literals are lvalues</h2> + +<pre><code class="language-c">(struct Foo){}; +((struct Foo){}).x = 4; +&amp;(struct Foo){}; +</code></pre> + +<h2 id="multi-character-constants">Multi-character constants</h2> + +<p>They are implementation dependent and even the standard itself to usually +best avoid them. That being said, using them as self-documenting <code>enum</code>s +can be quite handy when you may need to deal with raw memory dumps later on.</p> + +<pre><code class="language-c">enum state { + waiting = 'WAIT', + running = 'RUN!', + stopped = 'STOP', +}; +</code></pre> + +<p>For example, on my machine I could localize <code>'WAIT'</code> like here:</p> +<pre><code>00001120: c3 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 .ff...........@. +00001130: f3 0f 1e fa e9 67 ff ff ff 55 48 89 e5 48 83 ec .....g...UH..H.. +00001140: 10 c7 45 fc <mark>54 49 41 57</mark> 8b 45 fc 89 c6 48 8d 05 ..E.<mark>TIAW</mark>.E...H.. +00001150: b0 0e 00 00 48 89 c7 b8 00 00 00 00 e8 cf fe ff ....H........... +00001160: ff b8 00 00 00 00 c9 c3 f3 0f 1e fa 48 83 ec 08 ............H...</code></pre> + +<h2 id="bit-fields">Bit fields</h2> + +<p>Declares a member with explicit width, in bits. Adjacent bit field members may +be packed to share and straddle the individual bytes.</p> + +<pre><code class="language-c">struct cat { + unsigned int legs : 3; // 3 bits for legs (0-4 fit in 3 bits) + unsigned int lives : 4; // 4 bits for lives (0-9 fit in 4 bits) +}; +</code></pre> + +<ul> + <li><a href="https://en.cppreference.com/w/c/language/bit_field">Bit fields - cppreference.com</a></li> + <li><a href="https://en.wikipedia.org/wiki/Bit_field">Bit field - Wikipedia</a></li> + <li><a href="https://stackoverflow.com/q/24933242/10247460">When to use bit-fields in C - Stack Overflow</a></li> +</ul> + +<h2 id="0-bit-fields">0 bit fields</h2> + +<ul> + <li><a href="https://stackoverflow.com/q/45916894/10247460">What does an unnamed zero length bit-field mean in C? - Stack Overflow</a></li> + <li><a href="https://stackoverflow.com/q/4297095/10247460">Practical Use of Zero-Length Bitfields - Stack Overflow</a></li> + <li><a href="https://www.ibm.com/docs/en/xcafbg/9.0.0?topic=SS3KZ4_9.0.0/com.ibm.xlcpp9.bg.doc/proguide/calgnbit.html">IBM Documentation - IBM Documentation</a></li> + <li><a href="https://en.cppreference.com/w/c/language/bit_field">Bit fields - cppreference.com</a></li> +</ul> + +<p><span></span></p> + +<p>Description from <a href="https://developer.arm.com/documentation/ka004594/latest">Arm Compiler 6 docs</a>:</p> + +<blockquote> + <p>A zero-length bit-field can be used to make the following changes:</p> + <ul> + <li>Creates a boundary between any bit-fields before the zero-length bit-field +and any bit-fields after the zero-length bit-field. Any bit-fields on +opposite sides of the boundary are treated as non-overlapping memory +locations. This has a consequence for C and C++ programs. The C and C++ +standards require both load and store accesses to a bit-field on one side +of the boundary to not access any bit-fields on the other side of the boundary.</li> + <li>Insert padding to align any bit-fields after the zero-length bit-field to +the next available natural boundary based on the type of the zero-length +bit-field. For example, <code>char:0</code> can be used to align to the next available +byte boundary, and <code>int:0</code> can be used to align to the next available word boundary.</li> + </ul> +</blockquote> + +<p>An example taken from the <a href="https://stackoverflow.com/a/26725041/10247460">SO answer</a> (with slight changes):</p> + +<blockquote> + <pre><code class="language-c">struct bar { + unsigned char x : 5; + unsigned short : 0; + unsigned char y : 7; +} +</code></pre> + + <p>The above in memory would look like this (assuming 16-bit <code>short</code>, ignoring endian):</p> + + <pre><code>char pad pad short boundary + | | | | + v v v v + xxxxx000 00000000 yyyyyyy0 +</code></pre> + + <p>The zero-length bit field causes the position to move to next <code>short</code> boundary +(or: be placed on the nearest natural alignment for the target platform). +We defined <code>short</code> to be 16-bit, so 16 minus 5 gives 11 bits of padding.</p> +</blockquote> + +<h2 id="volatile-type-qualifier"><code>volatile</code> type qualifier</h2> + +<p>This qualifier tells the compiler that a variable may be accessed by other means +than the current code (e.g. we are dealing with MMIO device), thus to not optimize +away reads and writes to this resource.</p> + +<p><span></span></p> + +<ul> + <li><a href="https://stackoverflow.com/q/246127/10247460">Why is volatile needed in C? - Stack Overflow</a></li> + <li><a href="https://www.youtube.com/watch?v=w3_e9vZj7D8">Advanced C: The UB and optimizations that trick good programmers.</a></li> + <li><a href="https://en.cppreference.com/w/c/language/volatile">volatile type qualifier - cppreference.com</a></li> + <li><a href="https://en.wikipedia.org/wiki/Volatile_(computer_programming)">volatile (computer programming) - Wikipedia</a></li> +</ul> + +<h2 id="restrict-type-qualifier"><code>restrict</code> type qualifier</h2> + +<p>By adding this type qualifier, a programmer hints to the compiler that for +the lifetime of the pointer, no other pointer will be used to access the object +to which it points. This allows the compiler to make optimizations (for example, +vectorization) that would not otherwise have been possible.</p> + +<p><span></span></p> + +<ul> + <li><a href="https://en.wikipedia.org/wiki/Restrict">restrict - Wikipedia</a></li> + <li><a href="https://en.cppreference.com/w/c/language/restrict">restrict type qualifier - cppreference.com</a></li> + <li><a href="https://www.ibm.com/docs/en/zos/2.5.0?topic=qualifiers-restrict-type-qualifier">The restrict type qualifier - IBM Documentation</a></li> +</ul> + +<h2 id="register-type-qualifier"><code>register</code> type qualifier</h2> + +<p>It suggests that the compiler stores a declared variable in a CPU register +(or some other faster location) instead of in random-access memory. +The location of a variable declared with this qualifier cannot be accessed +(but the <code>sizeof</code> operator can be applied).</p> + +<p>Nowadays <code>register</code> is usually meaningless as modern compilers place variables +in a register if appropriate regardless of whether the hint is given. Sometimes +may it be useful on embedded systems, but even then compiler will probably +provide better optimizations.</p> + +<h2 id="flexible-array-member">Flexible array member</h2> + +<p>From Wikipedia:</p> + +<pre><code class="language-c">struct vectord { + short len; // there must be at least one other data member + double arr[]; // the flexible array member must be last + + // The compiler may reserve extra padding space here, + // like it can between struct members. +}; + +struct vectord *vector = malloc(...); +vector-&gt;len = ...; +for (int i = 0; i &lt; vector-&gt;len; ++i) { + vector-&gt;arr[i] = ...; // transparently uses the right type (double) +} +</code></pre> + +<ul> + <li><a href="https://gustedt.wordpress.com/2011/03/14/flexible-array-member/">flexible array member – Jens Gustedt's Blog</a></li> + <li><a href="https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html">Zero Length (Using the GNU Compiler Collection (GCC))</a></li> + <li><a href="https://developers.redhat.com/articles/2022/09/29/benefits-limitations-flexible-array-members">The benefits and limitations of flexible array members | Red Hat Developer</a></li> +</ul> + +<h2 id="n-format-specifier"><code>%n</code> format specifier</h2> + +<p><a href="https://stackoverflow.com/a/8930383/10247460">This StackOverflow answer</a> presents it reasonably well:</p> + +<blockquote> + <p><code>%n</code> returns the current position of the imaginary cursor used when <code>printf()</code> formats its output.</p> + + <pre><code class="language-c">int pos1, pos2; +const char* str_of_unknown_len = "we don't care about the length of this"; + +printf("Write text of unknown %n(%s)%n length\n", &amp;pos1, str_of_unknown_len, &amp;pos2); +printf("%*s\\%*s/\n", pos1, " ", pos2-pos1-2, " "); +printf("%*s", pos1+1, " "); +for (int i = pos1+1; i &lt; pos2-1; ++i) { + putc('-', stdout); +} +putc('\n', stdout); +</code></pre> + + <p>will have following output</p> + + <pre><code>Write text of unknown (we don't care about the length of this) length + \ / + -------------------------------------- +</code></pre> + + <p>Granted a little bit contrived but can have some uses when making pretty reports.</p> +</blockquote> + +<h2 id="-minimum-field-width-format-specifier"><code>%.*</code> (minimum field width) format specifier</h2> + +<p>Instead of this:</p> +<pre><code class="language-c">char fmt_buf[MAX_BUF]; +snprintf(fmt_buf, MAX_BUF, "%%.%df", prec); +printf(fmt_buf, num); +</code></pre> +<p>do this:</p> +<pre><code>printf("%.*f", prec, num); +</code></pre> +<p>when you want to pad with variable number of characters.</p> + +<h2 id="other-less-known-format-specifiers">Other less known format specifiers</h2> + +<p>Have a look at <a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#%5B%7B%22num%22%3A703%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C0%2C792%2C0%5D">§7.21.6.1</a> +and <a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#%5B%7B%22num%22%3A719%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C0%2C792%2C0%5D">§7.21.6.2</a> +of the draft of C11 standard. You'll find <code>%#</code>, <code>%e</code>, <code>%-</code>, <code>%+</code>, <code>%j</code>, <code>%g</code>, <code>%a</code> and few other interesting specifiers.</p> + +<aside> + <p>I'll update the links to C23 when it's finally done. For now: <code>%b</code> is gonna be standardised!</p> +</aside> + +<h2 id="interlacing-syntactic-constructs">Interlacing syntactic constructs</h2> + +<p>The following is syntactically correct C code:</p> +<pre><code class="language-c">#include &lt;stdio.h&gt; + +int main() +{ + int n = 3; + int i = 0; + + switch (n % 2) { + case 0: + do { + ++i; + case 1: + ++i; + } while (--n &gt; 0); + + } + + printf("%d\n", i); // 5 +} +</code></pre> + +<p>I know <code>goto</code>phobic programmers using it like this:</p> +<pre><code class="language-c"> switch (x) { + case 1: + // 1 specific code + + if (0) { + case 2: + // 2 specific code + } + + // common for 1 and 2 + } +</code></pre> + +<p>The most famous usage of this quirk/"feature" is <a href="https://en.wikipedia.org/wiki/Duff%27s_device">Duff's device</a>:</p> +<pre><code class="language-c">send(to, from, count) + register short *to, *from; + register count; +{ + register n = (count + 7) / 8; + switch (count % 8) { + case 0: do { *to = *from++; + case 7: *to = *from++; + case 6: *to = *from++; + case 5: *to = *from++; + case 4: *to = *from++; + case 3: *to = *from++; + case 2: *to = *from++; + case 1: *to = *from++; + } while (--n &gt; 0); + } +} +</code></pre> + +<h2 id="---operator"><code>--&gt;</code> "operator"</h2> + +<p>The following is correct C code:</p> + +<pre><code class="language-c">size_t n = 10; +while (n --&gt; 0) { + printf("%d\n", n); +} +</code></pre> + +<p>You may ask, since when C has such operator and the answer is: since never. +<code>--&gt;</code> is not an operator, but two separate operators <code>--</code> and <code>&gt;</code> written +in a way they look like one. It's possible, because C cares less than more +about whitespace.</p> + +<p><code>n --&gt; 0</code> is equivalent of <code>(n--) &gt; 0</code></p> + +<h2 id="idxarr"><code>idx[arr]</code></h2> + +<p>Square brace notation of accessing array elements is a syntactic sugar for pointer arithmetics:</p> + +<div style="width:100%; text-align:center"> + <p><code>arr[5]</code> ≡ <code>*(arr + 5)</code> ≡ <code>*(5 + arr)</code> ≡ <code>5[arr]</code></p> +</div> + +<p>You absolutely must never use this in actual code… but it's hella fun otherwise!</p> + +<pre><code class="language-c">// array[index] +boxes[products[myorder.product].box].weight; + +// index[array] +myorder.product[products].box[boxes].weight; +</code></pre> + +<h2 id="negative-array-indexes">Negative array indexes</h2> + +<p>For quick and dirty debugging purposes I wanted to check if padding at the end +of an array is filled with correct value, but I didn't know where the padding +starts. Thus I did the following:</p> + +<pre><code class="language-c">int* end = arr + (len - 1); +if (end[0] == VAL &amp;&amp; end[-1] == VAL &amp;&amp; end[-5] == VAL) { + puts("Correct padding"); +} +</code></pre> + +<h2 id="constant-string-concatenation">Constant string concatenation</h2> + +<p>You don't need <code>sprintf()</code> (nor <code>strcat()</code>!) to concatenate strings literals:</p> + +<pre><code>#define WORLD "World!" +const char* s = "Hello " WORLD "\n" + "It's a lovely day, " + "innit?"; +</code></pre> + +<h2 id="using--and--as-conditionals">Using <code>&amp;&amp;</code> and <code>||</code> as conditionals</h2> + +<p>If you write Shell scripts, you know what I mean.</p> + +<pre><code class="language-c">#include &lt;stdio.h&gt; +#include &lt;stdbool.h&gt; + +int main(void) +{ + 1 &amp;&amp; puts("Hello"); + 0 &amp;&amp; puts("I won't"); + 1 &amp;&amp; puts("World!"); + 0 &amp;&amp; puts("be printed"); + 1 || puts("I won't be printed either"); + 0 || puts("But I will!"); + + true &amp;&amp; (9 &gt; 2) &amp;&amp; puts("9 is bigger than 2"); + + isdigit('9') &amp;&amp; puts("9 is a digit"); + isdigit('n') &amp;&amp; puts("n is a digit") || puts("n is NOT a digit!"); + + return 0; +} +</code></pre> + +<p>The compiler will probably scream warnings at you +as it's really uncommon to do this in C code.</p> + +<h2 id="compile-time-assumption-checking-using-enums"><a href="https://stackoverflow.com/a/1715239/10247460">Compile time assumption checking using <code>enum</code>s</a></h2> + +<pre><code class="language-c">#define D 1 +#define DD 2 + +enum CompileTimeCheck +{ + MAKE_SURE_DD_IS_TWICE_D = 1/(2*(D) == (DD)), + MAKE_SURE_DD_IS_POW2 = 1/((((DD) - 1) &amp; (DD)) == 0) +}; +</code></pre> + +<p>Can be useful for libraries with compile-time configurable constants.</p> + +<h2 id="ad-hoc-struct-declaration-in-the-return-type-of-a-function">Ad hoc <code>struct</code> declaration in the return type of a function</h2> + +<p>You can define <code>struct</code>s in very (at first glance) random places:</p> + +<pre><code class="language-c">#include &lt;stdio.h&gt; + +struct Foo { int a, b, c; } make_foo(void) { + struct Foo ret = { .c = 3 }; + ret.a = 11 + ret.c; + ret.b = ret.a * 3; + return ret; +} + +int main() +{ + struct Foo x = make_foo(); + printf("%d\n", x.a + x.b + x.c); + return 0; +} +</code></pre> + +<h2 id="nested-struct-definition-is-not-kept-nested">"Nested" <code>struct</code> definition is not kept nested</h2> + +<pre><code class="language-c">#include &lt;stdio.h&gt; + +struct Foo { + int x; + struct Bar { + int y; + }; +}; + +int main() +{ + struct Bar s = { 34 }; // correct + // struct Foo.Bar s; // wrong + printf("%d\n", s.y); + return 0; +} +</code></pre> + +<h2 id="flat-initializer-lists">Flat initializer lists</h2> + +<pre><code>int arr[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; +// = { {1,2,3}, {4,5,6}, {7,8,9} }; + + +struct Foo { + const char *name; + int age; +}; + +struct Foo records[] = { + "John", 20, + "Bertha", 40, + "Andrew", 30, +}; +</code></pre> + +<h2 id="static-array-indices-in-function-parameter-declarations"><a href="https://www.ibm.com/docs/en/i/7.5?topic=pd-static-array-indices-in-function-parameter-declarations-c-only">Static array indices in function parameter declarations</a></h2> + +<blockquote> + <p>Except in certain contexts, an unsubscripted array name (for example, <code>region</code> +instead of <code>region[4]</code>) represents a pointer whose value is the address of the +first element of the array, provided that the array has previously been declared. +An array type in the parameter list of a function is also converted to the +corresponding pointer type. Information about the size of the argument array +is lost when the array is accessed from within the function body.</p> + + <p>To preserve this information, which is useful for optimization, C99 allows you +to declare the index of the argument array using the static keyword. The constant +expression specifies the minimum pointer size that can be used as an assumption +for optimizations. This particular usage of the static keyword is highly prescribed. +The keyword may only appear in the outermost array type derivation and only in +function parameter declarations. If the caller of the function does not abide +by these restrictions, the behavior is undefined.</p> + + <p>The following examples show how the feature can be used.</p> + + <pre><code class="language-c">int n; +void foo(int arr[static 10]); // arr points to the first of at least 10 ints +void foo(int arr[const 10]); // arr is a const pointer +void foo(int arr[const]); // const pointer to int +void foo(int arr[static const n]); // arr points to at least n ints (VLA) +</code></pre> +</blockquote> + +<p><code>void foo(int p[static 1]);</code> is effectively a standard +way to declare that <code>p</code> must be non-null pointer.</p> + +<h2 id="macro-overloading-by-argument-list-length">Macro Overloading by Argument List Length</h2> + +<ul> + <li><a href="https://github.com/Jorengarenar/CMObALL">CMObALL</a></li> + <li><a href="https://www.boost.org/doc/libs/master/libs/preprocessor/doc/ref/overload.html">BOOST_PP_OVERLOAD</a></li> + <li><a href="https://stackoverflow.com/q/16683146/10247460">Can macros be overloaded by number of arguments? - Stack Overflow</a></li> +</ul> + +<pre><code class="language-c">#include &lt;stdio.h&gt; +#include "cmoball.h" + +#define NoA(...) CMOBALL(FOO, __VA_ARGS__) +#define FOO_3(x,y,z) "Three" +#define FOO_2(x,y) "Two" +#define FOO_1(x) "One" +#define FOO_0() "Zero" + + +int main() +{ + puts(NoA()); + puts(NoA(1)); + puts(NoA(1,1)); + puts(NoA(1,1,1)); + return 0; +} +</code></pre> + +<h2 id="function-types">Function types</h2> + +<p>Function pointers ought to be well known, but as we know the syntax is bit awkward. +On the other hand, less people know you can (as with most objects in C) create +a <code>typedef</code> for function type.</p> + +<pre><code>#include &lt;stdio.h&gt; + +int main() +{ + typedef double fun_t(double); + fun_t sin, cos, sqrt; + fun_t* ftpt = &amp;sqrt; + + printf("%lf\n", ftpt(4)); // 2.000000 + + return 0; +} +</code></pre> + +<h2 id="x-macros">X-Macros</h2> + +<ul> + <li><a href="https://en.wikipedia.org/wiki/X_Macro">X Macro - Wikipedia</a> + <ul> + <li><a href="https://en.wikibooks.org/wiki/C_Programming/Preprocessor#X-Macros">Wikibooks on X macros</a></li> + <li><a href="https://en.wikibooks.org/wiki/C_Programming/Serialization#X-Macros">C Programming/Serialization/X-Macros</a></li> + </ul> + </li> + <li><a href="https://stackoverflow.com/q/6635851/10247460">Real-world use of X-Macros - Stack Overflow</a></li> + <li><a href="https://quuxplusone.github.io/blog/2021/02/01/x-macros/">What are X-macros? – Arthur O'Dwyer</a></li> + <li><a href="https://bbs.archlinux.org/viewtopic.php?id=272242">X macro: most epic C trick or worst abuse of preprocessor? / Arch Linux Forums</a></li> + <li><a href="https://philliptrudeau.com/blog/x-macro">The Most Elegant Macro – Phillip Trudeau</a></li> +</ul> + +<h2 id="named-function-parameters">Named function parameters</h2> + +<pre><code class="language-c">struct _foo_args { + int num; + const char* text; +}; + +#define foo(...) _foo((struct _foo_args){ __VA_ARGS__ }) +int _foo(struct _foo_args args) +{ + puts(args.text); + return args.num * 2; +} + +int main(void) +{ + int result = foo(.text = "Hello!", .num = 8); + return 0; +} +</code></pre> + +<h2 id="combining-default-named-and-positional-arguments"><a href="https://www.reddit.com/r/C_Programming/comments/yjbe62">Combining default, named and positional arguments</a></h2> + +<blockquote> + <p>Using compound literals and macros to create named arguments (…):</p> + + <pre><code class="language-c">typedef struct { int a,b,c,d; } FooParam; +#define foo(...) foo((FooParam){ __VA_ARGS__ }) +void (foo)(FooParam p); +</code></pre> + + <p>adding default arguments is also quite easy:</p> + + <pre><code class="language-c">#define foo(...) foo((FooParam){ .a=1, .b=2, .c=3, .d=4, __VA_ARGS__}) +</code></pre> + + <p>But now positional arguments don't work anymore, and there may be situations +where you want to support both options. But I recently realized, that you can +make them work by adding a dummy parameter:</p> + + <pre><code class="language-c">typedef struct { int _; int a,b,c,d; } FooParam; +#define foo(...) foo((FooParam){ .a=1, .b=2, .c=3, .d=4, ._=0, __VA_ARGS__}) +</code></pre> + + <p>Now, foo can be called in the following ways:</p> + + <pre><code class="language-c">foo(); // a=1, b=2, c=3, d=4 +foo(.a=4, .b=5); // a=4, b=5, c=3, d=5 +foo(4, 5); // a=4, b=5, c=3, d=5 +foo(4, 5, .d=8); // a=4, b=5, c=3, d=8 +</code></pre> + + <p>The dummy parameter isn't needed when you have arguments that are required to be passed by name:</p> + + <pre><code class="language-c">typedef struct { int alwaysNamed; int a,b,c,d; } FooParam; +#define foo(...) foo((FooParam){.a=1,.b=2,.c=3,.d=4, .alwaysNamed=5, __VA_ARGS__}) +</code></pre> +</blockquote> + +<h2 id="abusing-unions-for-grouping-things-into-namespaces"><a href="https://utcc.utoronto.ca/~cks/space/blog/programming/CUnionsForNamespaces">Abusing unions for grouping things into namespaces</a></h2> + +<blockquote> + <p>Suppose that you have a <code>struct</code> with a bunch of fields, and you want to deal +with some of them all together at once under a single name; perhaps you want +to conveniently copy them as a block through <code>struct</code> assignment.</p> + + <p>By using unions you can access both <code>a.field2</code> and <code>a.sub</code> (and <code>a.field2</code> +is the same as <code>a.sub.field2</code>) without any macros.</p> + + <pre><code class="language-c">struct a { + int field1; + union { + struct { + int field2; + int field3; + }; + struct { + int field2; + int field3; + } sub; + }; +}; +</code></pre> +</blockquote> + +<h2 id="matching-character-classes-with-sscanf">Matching character classes with <code>sscanf()</code></h2> + +<p>From <a href="https://www.reddit.com/r/programming/comments/116iij3/few_lesser_known_tricks_quirks_and_features_of_c/j98zxu5/">this comment</a> on Reddit:</p> + +<blockquote> + <p><code>sscanf()</code> can be used as an ersatz "regex" (not really, only character classes) matcher. +For example, one can write something like this to check if the input consists of letters of underscores:</p> + + <pre><code class="language-c">int len = 0; +char buf[256]; +int read_token = sscanf(input, "%255[a-zA-Z_]", buf, &amp;len); +if (read_token) { /* do something */ } +</code></pre> + + <p>or skip whitespace characters:</p> + + <pre><code class="language-c">int len = 0; +char buf[256]; +sscanf(input, "%255[\r\n]%n", buf, &amp;len); +input += len; +</code></pre> +</blockquote> + +<h2 id="garbage-collector">Garbage collector</h2> + +<p><a href="https://www.hboehm.info/gc/">Boehm GC</a> is a library providing garbage collector for C and C++</p> + +<h2 id="cosmopolitan-libc"><a href="https://justine.lol/cosmopolitan/index.html">Cosmopolitan Libc</a></h2> + +<p>Description from project's website:</p> + +<blockquote> + <p>Cosmopolitan Libc makes C a build-once run-anywhere language, like Java, +except it doesn't need an interpreter or virtual machine. Instead, it +reconfigures stock GCC and Clang to output a POSIX-approved polyglot format +that runs natively on Linux + Mac + Windows + FreeBSD + OpenBSD + NetBSD + BIOS +with the best possible performance and the tiniest footprint imaginable.</p> +</blockquote> + +<h2 id="inline-assembly">Inline assembly</h2> + +<p>For a high-level language C communicates quite well with low-level world. You +can write Assembly code and link it against program written in C quite easily. +In addition to that, many compilers offer as an extension (listed as common +in Annex J of the C Standard) a feature called <em>inline assembly</em>, typically +introduced to the code by the <code>asm</code> keyword.</p> + +<ul> + <li><a href="https://wiki.osdev.org/Inline_assembly">Inline Assembly - OSDev Wiki</a></li> + <li><a href="https://en.cppreference.com/w/c/language/asm">Inline assembly - cppreference.com</a></li> + <li><a href="https://learn.microsoft.com/en-us/cpp/c-language/inline-assembler-c">Inline Assembler (C) | Microsoft Learn</a></li> + <li><a href="https://developer.arm.com/documentation/100748/0619/Using-Assembly-and-Intrinsics-in-C-or-C---Code/Writing-inline-assembly-code">Writing inline assembly code - Arm Compiler for Embedded User Guide</a></li> + <li><a href="https://www.cs.uaf.edu/courses/cs301/2014-fall/notes/inline-assembly/">Inline Assembly in C/C++ - University of Alaska Fairbanks</a></li> +</ul> + +<h2 id="object-oriented-programming">Object Oriented Programming</h2> + +<ul> + <li><a href="https://www.state-machine.com/oop">Object-Oriented Programming in C - Quantum Leaps</a></li> + <li><a href="https://stackoverflow.com/q/415452/10247460">Object-orientation in C - Stack Overflow</a></li> + <li><a href="https://www.cs.rit.edu/%7Eats/books/ooc.pdf">Object-Oriented Programming With ANSI C</a></li> + <li><a href="https://www.cs.tufts.edu/comp/40/docs/CTrapsAndPitfalls.pdf">C Traps and Pitfalls</a> by Andrew Koenig</li> + <li><a href="https://www.reddit.com/r/C_Programming/comments/mqk338/interesting_ways_to_use_c/guhenr5/">"you can have something like interfaces and virtual methods by using function pointers"</a></li> +</ul> + +<h2 id="metaprogramming">Metaprogramming</h2> + +<p>C11 added <code>_Generic</code> to language, but turns out metaprogramming +by inhumanely abusing the preporcessor is possible even in pure C99: +meet <a href="https://metalang99.readthedocs.io"><strong>Metalang99</strong></a> library.</p> + +<pre><code>#include &lt;datatype99.h&gt; + +datatype( + BinaryTree, + (Leaf, int), + (Node, BinaryTree *, int, BinaryTree *) +); + +int sum(const BinaryTree *tree) { + match(*tree) { + of(Leaf, x) return *x; + of(Node, lhs, x, rhs) return sum(*lhs) + *x + sum(*rhs); + } + + return -1; +} +</code></pre> + +<h2 id="evaluate-sizeof-at-compile-time-by-causing-duplicate-case-error">Evaluate <code>sizeof</code> at compile time by causing duplicate case error</h2> + +<p>Assume you are working on embedded system or generally on something +where getting a <code>printf()</code> output may not be trivial task.</p> + +<pre><code>int foo(int c) +{ + switch (c) { + case sizeof (struct Foo): return c + 1; + case sizeof (struct Foo): return c + 2; + } +} +</code></pre> + +<p>Adding such simple function anywhere in your code may (depending on compiler) +produce an error message telling us the result of <code>sizeof</code> operator.</p> +<pre><code>error: duplicate case value '16' + case sizeof(struct Foo): return c + 2; + ^ +</code></pre>JorengarenarThere are some tricks, quirks and features (some quite fundamental to the language!) which seems to throw even experienced developers off the track. Thus I did a sloppy job of gathering some of them in this post (in no particular order) with even sloppier short explanations and/or examples (or quote of thereof).When VLA in C doesn't smell of rotten eggs2023-02-10T00:00:00+00:002023-02-10T00:00:00+00:00https://blog.joren.ga/vla-usecases<p>An earlier version of my <a href="/vla-pitfalls">Pitfalls of VLA in C</a> article contained +an example of useful case of VLA, which I pulled out of it as I decided the two +– although I'd be overjoyed being presented with more – cases where VLA +are clearly useful, deserve their dedicated, if low effort, post.</p> + +<h1 id="size-check-when-passing-to-function">Size check when passing to function</h1> + +<p>"Only" a bit over two decades after the introduction of VLA to C language, +GCC started giving warnings about passing to functions bigger than declared +size of arrays when we actually decide to utilize VLA syntax in parameters.</p> + +<pre><code class="language-c">#include &lt;stdio.h&gt; + +void f(const size_t size, const int buf[static size]); + +int main(void) +{ + int arr[50] = { 0 }; + f(10, arr); // acceptable + f(50, arr); // correct + f(100, arr); // *WARNING* + return 0; +} +</code></pre> + +<p><strong>Added bonus:</strong> explicit size annotation</p> + +<h1 id="multidimensional-arrays">Multidimensional arrays</h1> + +<p>Dynamically allocating multi-dimensional arrays where the inner dimensions +are not known until runtime is really simplified using VM types. +It isn't even as unsafe as aVLA since there's no arbitrary stack allocation.</p> + +<pre><code class="language-c">int (*arr)[n][m] = malloc(sizeof *arr); // `n` and `m` are variables with dimensions +if (arr) { + // (*arr)[i][j] = ...; + free(arr); +} +</code></pre> + +<p>The VLA-free alternatives aren't as sexy:</p> + +<ul> + <li><strong>piecemeal allocation with <code>malloc()</code></strong> + <pre><code class="language-c">int** arr = malloc(n * (sizeof *arr)); +if (arr) { +for (int i = 0; i &lt; n; ++i) { + arr[i] = malloc(m * (sizeof *arr[i])); +} +// arr[i][j] = ... +for (int i = 0; i &lt; n; ++i) { + free(arr[i]); +} +free(arr); +} +</code></pre> + </li> + <li><strong>1D array with offsets</strong> + <pre><code class="language-c">int* arr = malloc(n * m * (sizeof *arr)); +if (arr) { +// arr[i*n + j] = ... +free(arr); +} +</code></pre> + </li> + <li><strong>big fixed array</strong> + <pre><code class="language-c">int arr[SAFE_SIZE][SAFE_SIZE]; // SAFE_SIZE must be safe for SAFE_SIZE*SAFE_SIZE +// arr[i][j] = ...; +</code></pre> + </li> +</ul>JorengarenarAn earlier version of my Pitfalls of VLA in C article contained an example of useful case of VLA, which I pulled out of it as I decided the two – although I'd be overjoyed being presented with more – cases where VLA are clearly useful, deserve their dedicated, if low effort, post.A brief overview of pseudo-random number generators and testing of our own simple generator2022-05-03T00:00:00+00:002022-05-03T00:00:00+00:00https://blog.joren.ga/brief-prng-paperJorengarenarPitfalls of VLA in C2021-07-05T00:00:00+00:002021-07-05T00:00:00+00:00https://blog.joren.ga/vla-pitfalls<blockquote> + <p>It generates much more code, and much <em>slower</em> code (and more fragile code), + than just using a fixed key size would have done ~ <a href="https://lkml.org/lkml/2018/3/7/621">Linus Torvalds</a></p> +</blockquote> + +<p>VLA (<strong>variable-length array</strong>, an array – <em>array</em>, not just block of memory +acting like one – that has size determined during runtime instead of at compile +time) is a feature introduced to C with the revision C99 of the standard. +A very useful feature one may think, and indeed… in some cases… +But since the world we live in is less than ideal, one needs to know well what +are the pitfalls of using VLA in their code before doing so.</p> + +<p>If you want to know the few cases when VLA may actually +be useful you can check <a href="/vla-usecases">my other blogpost</a>.</p> + +<p>A fair share of the text here will focus on problems caused by automatic VLA, +thus to further reflect on that an abbreviation <em>aVLA</em> will be used when +refferng to those cases.</p> + +<h1 id="allocation-on-stack">Allocation on stack</h1> + +<p>Let's address the elephant in the room: aVLA usually are allocated on stack. +This is the source of the most of the problems, the source of discontent among +programmers, the reason why even allowing any VLA into the codebase is usually +a code smell.</p> + +<p>Let's consider a painfully simple, very favourable to aVLA, example:</p> +<pre><code class="language-c">#include &lt;stdio.h&gt; + +int main(void) { + int n; + scanf("%d", &amp;n); + char arr[n]; + printf("%d", arr[0]); + return 0; +} +</code></pre> + +<p>As we can see, it takes a number from user then makes array of that size. Compile +and try it. Check how big values you can input before getting segfault caused +by stack overflow. <a href="https://godbolt.org/z/45arWxWo7">In my case, it was around 8 MiB</a>. +How much is that? One raw image? a MP3 or two? few seconds of video? And the program +wasn't doing anything meaningful - what if it wasn't just <code>main()</code>? Maybe a recursive +function? The limit shrinks tremendously.</p> + +<p>And you don't have any (portable, standard) way to react after a stack +overflow - the program already <em>crashed, you lost control</em>. So you either need +to make elaborate checks before declaring an array or betting that user won't +input too large values (the outcome of such gamble ought to be obvious).</p> + +<p>So the programmer <strong>must</strong> ensure that aVLA size doesn't exceed some safe maximum, +but in reality, if you know safe maximum, there is rarely any reason for not using +it always.</p> + +<h2 id="worst-of-it-is">Worst of it is…</h2> + +<p>… that segfault is actually one of the best outcomes of improperly handled aVLA. +The worst case is an exploitable vulnerability, where attacker may choose a value +that causes an array to overlap with other allocations, giving them control over +those values as well. A security nightmare.</p> + +<aside> + <p>At the cost of further drop of efficiency, in GCC you can enable +<code>-fstack-clash-protection</code> option. It adds <em>extra</em> instructions around +variable length stack memory allocations to probe each page of memory at +allocation time. This mitigates stack-clash attacks by ensuring all stack +memory allocations are valid or by throwing a segfault if they are not, thus +turning a possible code-execution attack into a denial of service.</p> +</aside> + +<h2 id="so-how-to-fix-this-example">So how to fix this example?</h2> + +<p>What if I need to let user define size and creating ridiculously large fixed +array would be too wasteful? It's simple: use <code>malloc()</code>!</p> +<pre><code class="language-c">#include &lt;stdio.h&gt; +#include &lt;stdlib.h&gt; + +int main(void) { + int n; + scanf("%d", &amp;n); + char* arr = malloc(n * (sizeof *arr)); + printf("%d", arr[0]); + free(arr); + return 0; +} +</code></pre> + +<p>In this case I was able to request over 4.5 GB before segfault. Almost few orders +of magnitude more! But I still got the segfault, right? Well, the difference +is in getting at least some* chance of checking the value returned by <code>malloc()</code> +and thus being able to, for example, inform the user about the error:</p> +<pre><code class="language-c"> char* arr = malloc(n * (sizeof *arr)); + if (arr == NULL) { + perror("malloc()"); // output: "malloc(): Cannot allocate memory" + } +</code></pre> +<aside> + <p>* Only "some" chance because while it usually doesn't cause problems, +operating systems may (and do) use something called <a href="https://en.wikipedia.org/wiki/Memory_overcommitment">memory overcommitment</a> +which rarely, but still, may be a little… <a href="https://www.win.tue.nl/~aeb/linux/lk/lk-9.html#ss9.6">broken sometimes</a>.</p> +</aside> + +<h3 id="but-i-cannot-use-malloc">"but I cannot use <code>malloc()</code>!"</h3> + +<p>I've encountered a counterargument, that as C is often used as a systems/embedded +language, there are situations where using <code>malloc()</code> may not even be possible.</p> + +<p>I'm basically going to repeat myself here, but it is really important:</p> + +<ol> + <li> + <p>Such device rather is not going to have a lot of stack either. So instead of +allocating dynamically, you (probably) should determine how much you need and +just always use that fixed amount.</p> + </li> + <li> + <p>When using aVLA on system with small amounts of stack, it's really easy to make +something which seems to work, but which blows your stack if your function gets +called from a deep call stack combined with the large amount of data.</p> + </li> + <li> + <p>If you always allocate fixed amounts of stack space everywhere, and you test +it, you know you're good. If you dynamically allocate on stack, you have to +test all your code paths with all the largest sizes of allocated space, which +is much harder and much easier to make a mistake. Don't make it even easier to +shoot yourself in the foot for no real advantage.</p> + </li> +</ol> + +<h1 id="creation-by-accident">Creation by accident</h1> + +<p>Unlike most other dangerous C functionality, aVLA doesn't have the barrier +of being not known. Many newbies learn to use them via trial and error, but +don't learn about the pitfalls. <br /> +The following is a simple mistake I observed even experienced developers making +(especially those with C++ background); it will silently create an aVLA when +it's clearly not necessary:</p> +<pre><code class="language-c">const int n = 10; +int A[n]; +</code></pre> +<p>Thankfully, any half-decent compiler would notice and optimize aVLA away, but… +what if it doesn't notice? Or what if, for some reason (safety?), the optimizations +were not turned on? But it surely isn't so much worse, right? Well…</p> + +<h1 id="way-slower-than-fixed-size">Way slower than fixed size</h1> + +<p>Without compiler optimizations a function with <a href="https://godbolt.org/z/Pe6sqEqv1">aVLA from previous +example</a> will result in <strong>7 times</strong> more Assembly +instructions than its <a href="https://godbolt.org/z/7h9zevrPq">fixed size counterpart</a> +before moving past the array definition (look at the body before <code>jmp .L2</code>). +But it's without optimizations, with them the produced Assembly is exactly the same.</p> + +<p>So <a href="https://godbolt.org/z/4qeYhzTbn">an example where aVLA is not used by mistake</a>:</p> +<pre><code class="language-c">#include &lt;stdio.h&gt; +void bar(int*, int); + +void foo(int n) { + +#if VLA + int A[n]; +#else + int A[1000]; // Let's make it bigger than 10! (or there won't be what to examine) +#endif + + for (int i = n; i--;) { + scanf("%d", &amp;A[i]); + } + bar(A, n); +} + +int main(void) { + foo(10); + return 0; +} +</code></pre> +<p>For our educational purposes in this example, <code>-O1</code> level of optimisation will +work best (as Assembly will be clearer and <code>-O2</code> won't help aVLA's case here +really much).</p> + +<p>When we compile aVLA version, before instructions corresponding to <code>for</code> loop, we get:</p> +<pre><code class="language-nasm">push rbp +mov rbp, rsp +push r14 +push r13 +push r12 +push rbx +mov r13d, edi +movsx r12, edi ; here aVLA "starts"... +sal r12, 2 ; +lea rax, [r12+15] ; +and rax, -16 ; +sub rsp, rax ; +mov r14, rsp ; ... and there "ends" +</code></pre> + +<p>The aVLA-free version on the other hand generates:</p> +<pre><code class="language-nasm">push r12 +push rbp +push rbx +sub rsp, 4000 ; this is caused by array definition +mov r12d, edi +</code></pre> + +<p>So not only fixed array spawns less code, but also way simpler code. +Why, aVLA even causes more overhead at the beginning of the function. +It's not so much more in the grand scheme of things, but it still isn't +just a pointer bump.</p> + +<p>But are those differences significant enough to care? +<a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=02361bc77888">Yes, they are</a>.</p> + +<h1 id="no-initialization">No initialization</h1> + +<p>To add more to the issue with inadvertent aVLA, the following isn't allowed:</p> +<pre><code class="language-c">int n = 10; +int A[n] = { 0 }; +</code></pre> +<p>Even with optimizations, initialisation isn't allowed for aVLA. So despite +wanting fixed size array and compiler being technically able to provide one, +it's won't work (and if it does… it's breaking the specification…).</p> + +<h1 id="mess-for-compiler-writers">Mess for compiler writers</h1> + +<p>Few months ago I saved a <a href="https://www.reddit.com/r/C_Programming/comments/jz2213/are_vlas_bad_even_if_theyre_not_allocated_on_the/gdc3hz6">comment</a> +on Reddit listing problems encountered with VLA from compiler writer perspective. +I'll allow myself to cite the listed issues:</p> + +<blockquote> + <ul> + <li>A VLA applies to a type, not an actual array. So you can create a <code>typedef</code> +of a VLA type, which "freezes" the value of the expression used, even if +elements of that expression change at the time the VLA type is applied</li> + <li>VLAs can occur inside blocks, and inside loops. This means allocating and +deallocating variable-sized data on the stack, and either screwing up all +the offsets, or needing to do things indirectly via pointers.</li> + <li>You can use <code>goto</code> into and out of blocks with active VLAs, with some things +restricted and some not, but the compiler needs to keep track of the mess.</li> + <li>VLAs can be used with multi-dimensional arrays.</li> + <li>VLAs can be used as pointer targets (so no allocation is done, but it still +needs to keep track of the variable size).</li> + <li>Some compilers allow VLAs inside structure definitions (I really have no idea +how that works, or at what point the VLA size is frozen, so that all instances +have the same VLA(s) sizes.)</li> + <li>A function can have dozens of VLAs active at any one time, with some being +created or destroyed at different times, or conditionally, or in loops.</li> + <li><code>sizeof</code> needs to be specially implemented for VLAs, and all the necessary +info (for actual VLAs, VLA-types, and hybrid VLA/fixed-size types and +arrays and pointed-to VLAs).</li> + <li>'VLA' is also the term used for multi-dimensional array parameters, where +the dimensions are passed by other parameters.</li> + <li>On Windows, with some compilers (GCC at least), declaring local arrays which +make the stack frame size over 4 KiB, mean calling a special allocator +(<code>__chkstk()</code>), as the stack can only grow a page at a time. When a VLA is +declared, since the compiler doesn't know the size, it needs to call +<code>__chkstk</code> for every such function, even if the size turns out to be small.</li> + </ul> +</blockquote> + +<p>And believe me, if you take a stroll around some C forums (or the meeting of +standard committee [sic!]) you will see even more different complaints.</p> + +<h1 id="reduced-portability">Reduced portability</h1> + +<p>Due to all previously presented problems, some compiler providers decided to +not fully support C99. The primary example is Microsoft with its MSVC. +The C Standard Committee also noticed the problem and with C11 revision +all instances of VLAs were made optional; C2x is partially reverts that decision +mandating VM types (aVLA are still optional; there is even a slight sentiment +towards deprecating them entirely, but removing something from the, nomen omen, +standard is way harder than putting it in).</p> + +<p>That means code using a VLA won't necessarily be compiled by a C11 compiler, +so you need, assuming you target for portability, to check whether it is +supported with <code>__STDC_NO_VLA__</code> macro and make version without (a)VLA as +fallback. Wait… if you need to implement VLA-free version either way then +what's the point of doubling the code and creating VLA in the first place?!</p> + +<aside> + <p>As a side note: C++ doesn't have VLA and nothing suggests +it ever will (other than as implementation extension).<br /> +Not a dealbreaker, but still point against VLA in C.</p> +</aside> + +<h1 id="nitpick-breaking-conventions">(nitpick) Breaking conventions</h1> + +<p>This one is more of a nitpick, but still another reason to dislike VLA. There +is a widely used convention of first passing object then its parameters, what +in terms of arrays means:</p> +<pre><code class="language-c">void foo(int** arr, int n, int m) { /* arr[i][j] = ... */ } +</code></pre> + +<p>C99 specified that array sizes need to be parsed immediately when encountered +within a function definition's parameter list, what means that when using VLA +you cannot do an equivalent of the above:</p> +<pre><code class="language-c">void foo(int arr[n][m], int n, int m) { /* arr[i][j] = ... */ } // INVALID! +</code></pre> + +<p>You need to break up with the convention and write:</p> +<pre><code class="language-c">void foo(int n, int m, int arr[n][m]) { /* arr[i][j] = ... */ } +</code></pre> + +<p>Alternatively, you could use the obsolete syntax (obsolescent even in +ANSI C; finally removed in C2x), but that would be pointless, as +compilers don't make parameters checks in such case, so any benefits +from using VLA would be lost.</p> +<pre><code class="language-c">void foo(int[*][*], int, int); +void foo(arr, n, n) + int n; + int m; + int arr[n][m] +{ + // arr[i][j] = ... +} +</code></pre> + +<aside> + <p>There is a chance a GCC extension - <em>forward declaration of parameters</em> - will +be standardized in C2x (assuming we reach consensus on the revision +of <a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2780.pdf">N2780</a>).</p> +</aside> + +<h1 id="conclusion">Conclusion</h1> + +<p>In short, refrain from using VLA and <strong>avoid automatic VLA like devil avoids +holy water</strong>; if your compiler has it, rather compile with <code>-Wvla</code> flag +or similar (and definitely with <code>-Wvla-larger-than=0</code> - this allows VM types, +while warning about aVLA).</p> + +<p>If you find yourself in one of the situations where VLA (or VM type) is a valid/good +solution, of course, do use them, but keep in mind the limits I've outlined here.</p> + +<aside> + <p>It's probably also worth mentioning that VLAs were partially supposed to be +a solution to non-standard <code>alloca()</code> function, which is even more problematic +when it comes to stack.</p> +</aside> + +<aside> + <p>As you could have guessed by the quote at the beginning, project which used to +rely on VLA quite extensively (209 unique locations reported in 60 directories!) +is nothing else than Linux kernel. Maintainers spent a lot of effort to get rid +of all VLA and as of version 4.20 (year 2018) it's completely VLA-free.</p> +</aside>JorengarenarIt generates much more code, and much slower code (and more fragile code), than just using a fixed key size would have done ~ Linus TorvaldsSteps to learn Vim2021-01-23T00:00:00+00:002021-01-23T00:00:00+00:00https://blog.joren.ga/vim-learning-steps<ol start="0"> + <li>Learn <a href="https://stackoverflow.com/help/how-to-ask">how to ask a good question</a> and <a href="https://ddg.gg/?q=vim+start+learning">to type it into search engine before asking</a> on forums</li> + <li>Do <a href="https://vimhelp.org/usr_01.txt.html#vimtutor"><code>vimtutor</code></a> - it's a 30-minute tutorial that teaches the most basic Vim functionality hands-on</li> + <li><a href="https://en.wikipedia.org/wiki/RTFM">RTFM</a>! User manual (<a href="https://vimhelp.org/usr_toc.txt.html"><code>:h user-manual</code></a>) will guide you through every feature from basic to advanced</li> + <li><a href="https://vimhelp.org/"><code>:help</code></a> and <code>:helpgrep</code> to find more detailed documentation of specific feature</li> + <li><a href="https://vimhelp.org/vim_faq.txt.html"><code>:h faq</code></a> - Frequently Asked Questions</li> + <li><a href="https://vimhelp.org/quickref.txt.html"><code>:h quickref</code></a> - quick reference guide</li> + <li><a href="https://github.com/romainl/idiomatic-vimrc">idiomatic vimrc</a> by <a href="http://romainl.github.io/">romainl</a></li> +</ol> + +<aside> + <p><strong><em>Ad 1:</em></strong> Additionaly you can also:</p> + <ul> + <li><a href="https://learnvim.irian.to">Learn Vim the Smart Way</a></li> + <li>Play free levels of <a href="https://vim-adventures.com">VIM Adventures</a></li> + <li>Follow <a href="https://openvim.com/">OpenVim</a> - an interactive Vim tutorial online</li> + <li>Try yourself in online <a href="https://vim.morzel.net">Vim Quiz</a></li> + </ul> +</aside> + +<aside> + <p>Further down the road:</p> + <ul> + <li>Read humorous <a href="https://blog.sanctum.geek.nz/vim-koans">Vim Kōans</a></li> + <li><a href="https://stackoverflow.com/a/1220118/10247460">Your problem with Vim is that you don't grok vi</a></li> + <li><a href="https://www.vi-improved.org/vim-proverbs">Proverbs</a> and <a href="https://www.vi-improved.org/recommendations">recommendations</a> from <a href="https://www.vi-improved.org/">#vim</a></li> + <li><a href="https://www.moolenaar.net/habits.html">Seven habits of effective text editing</a> by Bram Moolenaar</li> + <li><a href="https://stackoverflow.com/a/26710166/10247460">Why do Vim experts prefer buffers over tabs?</a></li> + <li><a href="https://www.reddit.com/r/vim/wiki/vimrctips">vimrctips</a> of <a href="https://www.reddit.com/r/vim">r/vim</a></li> + <li><a href="https://www.youtube.com/watch?v=XA2WjJbmmoM">How to Do 90% of What Plugins Do (With Just Vim)</a></li> + <li><a href="https://learnvimscriptthehardway.stevelosh.com">Learn Vimscript the Hard Way</a></li> + <li><a href="/vim-xdg">Make Vim follow XDG Base Directory specification</a></li> + <li>Watch some <a href="http://vimcasts.org/episodes">Vimcasts</a></li> + <li>Check out <a href="https://vimways.org/2018">Vimways</a></li> + <li>Read configs of more experienced users (<a href="https://github.com/Jorengarenar/dotfiles/tree/master/vim">here's mine</a>, for example)</li> + <li>Check out resource lists: + <ul> + <li>My <a href="https://resources.joren.ga">list of resources</a> on various topics (filter by "<em>Vim</em>" tag)</li> + <li><a href="https://learnbyexample.github.io/curated_resources/vim.html">Vim - Curated learning resources</a></li> + </ul> + </li> + </ul> +</aside>JorengarenarLearn how to ask a good question and to type it into search engine before asking on forums Do vimtutor - it's a 30-minute tutorial that teaches the most basic Vim functionality hands-on RTFM! User manual (:h user-manual) will guide you through every feature from basic to advanced :help and :helpgrep to find more detailed documentation of specific feature :h faq - Frequently Asked Questions :h quickref - quick reference guide idiomatic vimrc by romainlMake Vim follow XDG Base Directory specification2020-12-13T00:00:00+00:002020-12-13T00:00:00+00:00https://blog.joren.ga/vim-xdg<p>XDG Base Directory specification, <code>$XDG_CONFIG_HOME</code> etc. Great thing - configs +separated from user data and cache, no clutter in home directory. Unfortunately, +many programs still don't respect it, including Vim. But what would be our favourite +text editor if we wouldn't be able to reconfigure it!</p> + +<h1 id="tldr">TL;DR</h1> + +<p>Into shell config (e.g. in <code>~/.profile</code>):</p> +<pre><code class="language-sh">export VIMINIT="set nocp | source ${XDG_CONFIG_HOME:-$HOME/.config}/vim/vimrc" +</code></pre> + +<p>At the top of <em>vimrc</em>:</p> +<pre><code class="language-vim">" XDG support + +if empty($MYVIMRC) | let $MYVIMRC = expand('&lt;sfile&gt;:p') | endif + +if empty($XDG_CACHE_HOME) | let $XDG_CACHE_HOME = $HOME."/.cache" | endif +if empty($XDG_CONFIG_HOME) | let $XDG_CONFIG_HOME = $HOME."/.config" | endif +if empty($XDG_DATA_HOME) | let $XDG_DATA_HOME = $HOME."/.local/share" | endif +if empty($XDG_STATE_HOME) | let $XDG_STATE_HOME = $HOME."/.local/state" | endif + +set runtimepath^=$XDG_CONFIG_HOME/vim +set runtimepath+=$XDG_DATA_HOME/vim +set runtimepath+=$XDG_CONFIG_HOME/vim/after + +set packpath^=$XDG_DATA_HOME/vim,$XDG_CONFIG_HOME/vim +set packpath+=$XDG_CONFIG_HOME/vim/after,$XDG_DATA_HOME/vim/after + +let g:netrw_home = $XDG_DATA_HOME."/vim" +call mkdir($XDG_DATA_HOME."/vim/spell", 'p', 0700) + +set backupdir=$XDG_STATE_HOME/vim/backup | call mkdir(&amp;backupdir, 'p', 0700) +set directory=$XDG_STATE_HOME/vim/swap | call mkdir(&amp;directory, 'p', 0700) +set undodir=$XDG_STATE_HOME/vim/undo | call mkdir(&amp;undodir, 'p', 0700) +set viewdir=$XDG_STATE_HOME/vim/view | call mkdir(&amp;viewdir, 'p', 0700) + +if !has('nvim') " Neovim has its own special location + set viminfofile=$XDG_STATE_HOME/vim/viminfo +endif +</code></pre> + +<h1 id="step-by-step">Step-by-step</h1> +<h2 id="relocating-vimrc">Relocating <em>vimrc</em></h2> + +<p>To begin with, since version 7.3.1178, Vim will search for <code>~/.vim/vimrc</code> if +<code>~/.vimrc</code> is not found. So let's move the file there.</p> + +<p>Let's move our <code>~/.vim</code> to <code>$XDG_CONFIG_HOME/vim</code>. Now we need to command Vim +to read config from this new location prior to <code>~/.vim</code>. There are three ways +to do it.</p> + +<h3 id="shell-alias">Shell alias</h3> + +<p>Pretty straightforward method. Shell will just substitute command <code>vim</code> with the alias body</p> + +<pre><code class="language-sh">alias vim='vim -u ${XDG_CONFIG_HOME:-$HOME/.config}/vim/vimrc' +</code></pre> + +<p>Downside? Works only in shell</p> + +<h3 id="viminit-environmental-variable"><code>VIMINIT</code> environmental variable</h3> + +<pre><code class="language-sh">export VIMINIT="set nocp | source ${XDG_CONFIG_HOME:-$HOME/.config}/vim/vimrc" +</code></pre> + +<p>Cons? If you wish for Neovim and Vim configurations to still be separated, then:</p> + +<pre><code class="language-sh">export VIMINIT="if has("nvim") | so ${XDG_CONFIG_HOME:-$HOME/.config}/nvim/init.vim | else | set nocp | so ${XDG_CONFIG_HOME:-$HOME/.config}/vim/vimrc | endif" +</code></pre> + +<h3 id="wrapper-script">Wrapper script</h3> + +<p>Save the following code as <code>vim</code> in <code>$HOME/.local/bin</code> * +and make is executable with <code>chmod +x vim</code></p> + +<pre><code class="language-sh">#!/usr/bin/env sh + +for dir in $(echo "$PATH" | tr ":" "\n" | grep -Fxv "$(dirname $0)"); do + if [ -x "$dir/vim" ]; then + exec "$dir/vim" -u "${XDG_CONFIG_HOME:-$HOME/.config}"/vim/vimrc "$@" + fi +done +</code></pre> + +<p>Doesn't affect Neovim and works outside shell, but you need to carry it together +with your config</p> + +<p>* Remember to add it to the beginning of <code>PATH</code> environment variable. <br /> +   It can be also other location of your choice instead of <code>$HOME/.local/bin</code></p> + +<h2 id="now-the-code-in-our-vimrc">Now the code in our <em>vimrc</em></h2> + +<p>First of all, although not mandatory, let's set <code>$MYVIMRC</code> variable:</p> +<pre><code class="language-vim">if empty($MYVIMRC) | let $MYVIMRC = expand('&lt;sfile&gt;:p') | endif +</code></pre> + +<p>Let's define fallback locations in case <code>XDG_*</code> variables are not set.</p> +<pre><code class="language-vim">if empty($XDG_CACHE_HOME) | let $XDG_CACHE_HOME = $HOME."/.cache" | endif +if empty($XDG_CONFIG_HOME) | let $XDG_CONFIG_HOME = $HOME."/.config" | endif +if empty($XDG_DATA_HOME) | let $XDG_DATA_HOME = $HOME."/.local/share" | endif +if empty($XDG_STATE_HOME) | let $XDG_STATE_HOME = $HOME."/.local/state" | endif +</code></pre> + +<p>Let's add entries to <code>runtimepath</code>:</p> +<pre><code class="language-vim">set runtimepath^=$XDG_CONFIG_HOME/vim +set runtimepath+=$XDG_DATA_HOME/vim +set runtimepath+=$XDG_CONFIG_HOME/vim/after +</code></pre> + +<p><code>$XDG_CONFIG_HOME/vim</code> and <code>$XDG_CONFIG_HOME/vim/after</code> are just equivalents of +<code>~/.vim</code> and <code>~/.vim/after</code>, but <code>$XDG_DATA_HOME/vim</code> is brand new - there we +will keep downloadables (like plugins and spell files), Netrw bookmarks etc.</p> + +<p>Let's set directory for Vim8 build-in packages:</p> +<pre><code class="language-vim">set packpath^=$XDG_DATA_HOME/vim +set packpath+=$XDG_DATA_HOME/vim/after +</code></pre> + +<p>Netrw is just as easy:</p> +<pre><code class="language-vim">let g:netrw_home = $XDG_DATA_HOME."/vim" +</code></pre> + +<p>What about spellings? Well, this one is more tricky, because it isn't controlled +by any option. Instead it searches for <code>spell</code> directory in whole runtime path. +If none is found then it falls back to <code>~/.vim/spell</code>. So let's create one at +desired location ourselves!</p> +<pre><code class="language-vim">call mkdir($XDG_DATA_HOME."/vim/spell", 'p', 0700) +</code></pre> + +<p>So far so good. We are left with state (backup, undo, swap, viminfo, view). +Vim doesn't create directories for them (even for defaults), so we will need +to do it ourselves - thankfully VimL has <code>mkdir()</code> function.</p> +<pre><code class="language-vim">set backupdir=$XDG_STATE_HOME/vim/backup | call mkdir(&amp;backupdir, 'p', 0700) +set directory=$XDG_STATE_HOME/vim/swap | call mkdir(&amp;directory, 'p', 0700) +set undodir=$XDG_STATE_HOME/vim/undo | call mkdir(&amp;undodir, 'p', 0700) +set viewdir=$XDG_STATE_HOME/vim/view | call mkdir(&amp;viewdir, 'p', 0700) + +if !has('nvim') " Neovim has its own location which already complies with XDG specification + set viminfofile=$XDG_STATE_HOME/vim/viminfo +endif +</code></pre> + +<p>Congratulations! Now your Vim is configured with accordance to XDG Base Directory specification.</p> + +<h1 id="sources">Sources</h1> +<ul> + <li><a href="https://tlvince.com/vim-respect-xdg">Vim respect XDG</a></li> + <li><a href="https://specifications.freedesktop.org/basedir-spec/0.8/">XDG Base Directory Specification</a></li> + <li><a href="https://github.com/vim/vim/issues/2034">Issue #2034: [RFC] .config/vim(UNIX), AppData/Roaming/vim(Windows) directory structure</a></li> + <li><a href="https://github.com/vim/vim/commit/6a459902592e2a4ba68">Version 7.3.1178 commit</a></li> + <li><a href="https://wiki.archlinux.org/index.php/XDG_Base_Directory">XDG Base Directory - ArchWiki</a></li> + <li><a href="https://github.com/Jorengarenar/dotfiles/tree/master/vim">Jorengarenar's Vim config</a></li> + <li><a href="https://groups.google.com/g/vim_dev/c/ieoldm29ymM/m/-dTZ2E8A1xwJ">[PATCH] XDG Base Directory Specification support</a></li> +</ul>JorengarenarXDG Base Directory specification, $XDG_CONFIG_HOME etc. Great thing - configs separated from user data and cache, no clutter in home directory. Unfortunately, many programs still don't respect it, including Vim. But what would be our favourite text editor if we wouldn't be able to reconfigure it!Best aspects of C language2020-11-03T00:00:00+00:002020-11-03T00:00:00+00:00https://blog.joren.ga/best-of-c<p>How comes that, after over half a century, C is still a relatively popular and +widely used language when others have withered into obscurity? Why, over all this +time, was nothing able to fully replace it? Why is it still taught in schools?</p> + +<p>Let's have a look at some of the best, in my opinion, aspects of the language +(although not all) that contributed to such a state of affairs.</p> + +<h1 id="spirit-of-c">Spirit of C</h1> + +<p>Let's start with a quote from document <a href="http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf">C99RationaleV5.10</a>:</p> + +<blockquote> + <p>The C89 Committee kept as a major goal to preserve the traditional spirit of C. +There are many facets of the spirit of C, but the essence is a community +sentiment of the underlying principles upon which the C language is based. +Some of the facets of the spirit of C can be summarized in phrases like:</p> + <ul> + <li><em>Trust the programmer.</em></li> + <li><em>Don’t prevent the programmer from doing what needs to be done.</em></li> + <li><em>Keep the language small and simple.</em></li> + <li><em>Provide only one way to do an operation.</em></li> + <li><em>Make it fast, even if it is not guaranteed to be portable.</em></li> + </ul> +</blockquote> + +<h1 id="mid-level">"Mid-level"</h1> + +<p>In regards of level, there are two types of languages: low and high.</p> + +<p>Low-level languages are close to the hardware, the only closer thing to CPU +would be electricity itself. Those languages are divided into machine code and +Assembly. The former is a stream of raw, usually binary, data. If somebody is +required to work with it, usually does it using more "readable" hexadecimal form.</p> + +<p>Second-generation languages - Assembly - provide one abstraction level on top +of the machine code. Those languages are mostly only a mapping of human-readable +symbols, including symbolic addresses, to opcodes, addresses, numeric constants, +strings and so on. Also are different for each processor.</p> + +<p>How do high-level languages, providing more abstraction, compare? Quoting Wikipedia:</p> + +<blockquote> + <p>In contrast to low-level programming languages, it may use natural language +elements, be easier to use, or may automate (or even hide entirely) significant +areas of computing systems (e.g. memory management), making the process of +developing a program simpler and more understandable than when using a +lower-level language. The amount of abstraction provided defines how +"high-level" a programming language is.</p> +</blockquote> + +<p>In big oversimplification: low = more machine friendly, high = more human friendly.</p> + +<p>C is high-level, but back when it was created, most of the work was still being +done in low-level Assembly. As a result, C has lower level of abstraction than +other (still) widely used languages and is often utilized for low-level +programming, hence I like to call it "mid-level".</p> + +<p>You can also easily (with less language bloat) compile C code to Assembly and +examine what instructions processor will execute.</p> + +<p>And if it there is a need, many popular C compilers offers you the option +to level down and use inline Assembly to squeeze everything out of CPU. +It's a feature not really implemented with many other languages.</p> + +<h1 id="fairly-simple">Fairly simple</h1> + +<p>Low-level languages are harder to program in. Not because they are more +complicated, but because they are more error prone and thus require way +more commitment, memorizing and fiddling.</p> + +<p>C is mid-level, so "by definition" it's easier. But there comes the surprise, +learning it is easier compared to higher level languages! Why? Because of not +extensive syntax it doesn't take so much to learn the basics. +Loops, functions, structures, pointers, variables, types - the core of language. +Intense week to get the general idea. The rest is "just" maths and CS theorem.</p> + +<p>But, but, but, but! Don't get me wrong! <br /> +Language is simple, programming not necessarily! <br /> +To master anything you will need a lot more practice! <br /> +<strong>A lot!</strong> And it's truth for anything out there!</p> + +<h1 id="fast-lightweight-and-flexible">Fast, lightweight and flexible</h1> + +<p>Standard C library is small compared to other languages (e.g. Java). It's small +enough for you to try to memorize all functions successfully (not that it would +be a huge benefit). Yeah, many things should be deprecated long ago, there +obviously is some bloat (try to maintains something without bloat for few years, +let alone few decades), but there is not much enough of it to hinder the performance.</p> + +<p>And what if libc is still too much? Nothing stands in the way of not using it +at all! Just don't include any of its headers - not even simple <code>printf()</code> will +be present. Replace it with any other library of your choice.</p> + +<p>Maturity, emphasis on proper memory management, inline Assembly, small abstraction +and little bloat gives programmer really good control over the program.</p> + +<p>This makes C an ideal choice for OS kernels (Linux, Windows NT or macOS's XNU to +name a few) or other languages (e.g. Python). That's also why C is so popular +on embedded systems, where you cannot afford to waste resources.</p> + +<h1 id="standard-no-blessed-implementation">Standard, no blessed implementation</h1> + +<p>This one relates to previous and next point. The C programming language is definied +basically only by a document published by International Organization for Standardization +every few years. Contrary to languages like Python, Rust or Java, there is no partucullar +implementation that is <strong>the</strong> C language.</p> + +<p>Combine it with flexibility and you have a language which can easily target any platform.</p> + +<h1 id="ubiquity--portability">Ubiquity = portability</h1> + +<p>Does there exist any (still) significant platform with no C compiler available? +Yes, those work exclusively on Assembly only; for all others, C is available. +C programs are present on your high-end gaming PC, on NASA spacecrafts and +in ticket machines. Literally everywhere. C software runs the world.</p> + +<p>In accordance to previous paragraphs, C is peculiarly strong choice for +microcontrollers and other forms of embedded systems, which surround us every day.</p> + +<p>And have you heard about <a href="https://en.wikipedia.org/wiki/Foreign_function_interface">FFI</a>? +Turns out many other languages like to have some kind of compatibility with C.</p> + +<p>You don't need to worry if you will be able to use this language somewhere as +for 99% you can! (Although it doesn't mean you should…) It means, that while +code may not be 100% portable, you will be a portable programmer.</p> + +<h1 id="the-influencer">The influencer</h1> + +<p>C has both directly and indirectly influenced innumerous amount of languages. +C++, Java, Go, D, Rust, Perl, even PHP and Python - those are but few examples.</p> + +<p>Obviously, knowledge of C isn't needed to learn any of them and sometimes +may even push you to use not the best practices.</p> + +<p>Nevertheless, I think it's beneficial to remember the roots. And if you are +cautious, familiarity with C might give you some foothold. It's especially the +case with C++.</p> + +<h1 id="rich-collection-of-libraries">Rich collection of libraries</h1> + +<p>I suspect all this talk about fastness, lightness, mid-level, Assembly etc. might +have give you an idea, you will need to implement everything yourself. There may +indeed not be any <a href="https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html"><code>LinkedHashMap</code></a> +or other functionalities like garbage collection available for C… except… not entirely.</p> + +<p>C is mature and popular language, so while those features aren't build-in, +believe me, name a thing and somebody somewhere already created library for +it (although if think about something too obscure to find, but it does exists).</p> + +<p>You want garbage collector? <a href="https://www.hboehm.info/gc/">Boehm GC</a> has you covered. +TUI? Nothing like timeless <a href="https://invisible-island.net/ncurses/">ncurses</a>. +Examples can be listed almost infinitely: +<a href="https://gtk.org/">GTK</a>, +<a href="https://pdcurses.org/">PDCurses</a>, +<a href="https://curl.haxx.se/libcurl/">libcurl</a>, +<a href="https://www.alsa-project.org/">ALSA</a>, +<a href="https://codeplea.com/genann">Genann</a>, +<a href="http://libsound.io/">libsoundio</a>, +<a href="https://libsdl.org">SDL</a>, +<a href="https://www.sqlite.org/index.html">SQLite</a>, +<a href="https://www.gnu.org/software/libc/manual/html_node/Getopt.html">getopt</a>, +<a href="https://www.opengl.org/">OpenGL</a>, +<a href="https://github.com/benhoyt/inih">inih</a>, +<a href="https://gmplib.org/">GMP</a>, +<a href="https://github.com/DaveGamble/cJSON">cJSON</a>, +<a href="https://mupdf.com/">MuPDF</a>, +<a href="https://github.com/Jorengarenar/libXDGdirs">libXDGdirs</a>, +<a href="https://www.openssl.org/">OpenSSL</a>…</p> + +<p>It's very universal language - you can program basically anything: web server, +video game (e.g. <a href="https://github.com/id-Software">classics from <em>id Software</em></a>), +operating system, other programming language or wrapper forcing Firefox to obey +<a href="https://wiki.archlinux.org/index.php/XDG_Base_Directory">XDG Base Directory specification</a>, +because when I'm an administrator, the programs will do exactly what I told them to! +There were madlads doing WebDev in C via CGI Scripts (and nowadays with WebAssembly).</p> + +<p>However, please, remember - the fact you can, doesn't mean you should. For example, +if you want to create a video game, you really ought to turn your eyes to C++. +And you should know, that…</p> + +<h1 id="c-is-highly-backward-compatible">C++ is highly backward compatible</h1> + +<p>Why do I even make the whole point out of C++ here? Because it's one of most +widely used languages today and you encountering it is more than certain.</p> + +<p>In contrary to other languages embracing C compatibility, C++ was created as its +direct descendant and committee goes to great lengths to keep the "copy-paste" +compatibility with it - in most cases you can compile C code as C++ just fine.</p> + +<aside> + <p>Don't be mistaken, +<a href="https://mcla.ug/blog/cpp-is-not-a-superset-of-c.html">C++ isn't by any means a superset of C</a> - the code +isn't always going to work with C++ and a good C code isn't necessary good C++ code. Consider example:</p> + <pre><code class="language-c">int* x = malloc(10 * sizeof (*x)); +</code></pre> + <p>Proper way in C, but in C++ there ought to be <code>(int*)</code> before <code>malloc()</code>, +for it to work, not to mention you should use <code>new int[10]</code> instead.</p> + + <p>Although in most cases you can use C library safely in your C++ project.</p> +</aside> + +<p>All examples from the previous point not only <strong>can be</strong>, but <strong>often are</strong> +used in such way.</p> + +<p>Even libraries already compiled with C compiler can be made compatible with C++, +thanks to <a href="https://en.cppreference.com/w/cpp/language/language_linkage"><code>extern "C"</code></a> +linkage specifier.</p> + +<h1 id="safety">Safety</h1> + +<p>In my opinion, <a href="https://www.reddit.com/r/C_Programming/comments/llwg2e/what_are_common_uses_of_c_in_the_real_world/gns54z3">this comment</a> +by Reddit user <a href="https://www.reddit.com/user/tim36272">u/tim36272</a> catches this point perfectly:</p> + +<blockquote> + <p>You're thinking of things like type safety, garbage collection etc.</p> + + <p>I'm talking about safety in terms of people dying. Things like garbage +collection are the opposite of life safety. What if your airplane decided it +needed to free up memory ten seconds from touchdown so it ran the garbage +collector? What if running the garbage collector caused a valve to respond +0.1 seconds late to a command, which caused a chain reaction resulting in +a hydraulic line bursting and losing control of the rudder?</p> + + <p>C can be safe because it does exactly what the programmer tells it to do, +nothing more and nothing less. There's no magic going on behind the scenes +which could have complex interactions with other behind the scenes magic.</p> + + <p>A common example is <code>std::vector</code> from C++. This container expands as needed +to accommodate as many elements as you need. But you have a limited amount of +memory on the system, so you need to do static analysis to determine the +maximum size of that vector. And you need to be sure that you have enough +memory for that plus everything else in your system.</p> + + <p>Well, now you've eliminated a lot of the convenience of using <code>std::vector</code>. +You might as well just allocate that max size to it and avoid all the overhead +<code>std::vector</code> imposes by growing in size.</p> + + <p>The other main advantage of <code>std::vector</code> are templates. If you were to use a +template in safety critical code you'd need to prove that the code generated by +the compiler is correct for every template. Now that you're diving down into +all this auto-generated machine code, it would be easier to just write the +code yourself and avoid the complexity introduced by the compiler's template +generator.</p> + + <p>So, if we eliminate all the usefulness of <code>std::vector</code>, why use it at all?</p> + + <p>Repeat that process for most features in most languages and voila! You're back at C</p> +</blockquote> + +<p><strong>Important note</strong>: if you want such safety, you throw portability out of the window!</p> + +<h1 id="preprocessor">Preprocessor</h1> + +<p>C (and its direct derivatives like C++ or Object-C) is the only language +I know of, which includes a lexical preprocessor in its specification.</p> + +<p>Understandable, considering the fact that many newer languages contain mechanisms +which make preprocessing partially obsolete.<br /> +And in the need there are always fallbacks:</p> +<ul> + <li>using other language (or even itself) as preprocessor (e.g. Python as preprocessor to Java)</li> + <li>using external preprocessor (e.g. <a href="https://www.gnu.org/software/m4/m4.html">m4</a>) + <ul> + <li>…or C preprocessor (yes, there is nothing stopping you from <a href="https://www.nongnu.org/espresso/js-cpp.html">preprocessing JavaScript with C compiler</a>!)</li> + </ul> + </li> +</ul> + +<p>I will repeat the link with proper title: +<a href="https://www.nongnu.org/espresso/js-cpp.html">The C Preprocessor in Javascript?</a> - +I really recommend reading this short text, as I think it's enought to understand +why having a standarized, portable preprocessor is a good thing in C.</p> + +<h1 id="program-in-c-song"><em>Program in C</em> song</h1> + +<div class="yt-container"> + <iframe class="yt-video" src="https://www.youtube.com/embed/tas0O586t80" frameborder="0" allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe> +</div> + +<details> + <summary>Lyrics</summary> + <em style="white-space: pre-line;"> + Ariel, listen to me + OO languages? + It's a mess. + Programming in C is better than anything they got over there. + + The syntax might seem much sweeter + Where objects and subtypes play + But frills like inheritance + Will only get in the way! + Admire C's simple landscape + Efficiently dangerous! + No templates or fancy pitfalls + ... like Java and C++! + + Program in C + Program in C + + Pointers, assembly, + Manage your memory + With malloc() and free()! + Don't sink your app with runtime bloat + Software in C will stay afloat + Do what you want there + Close to the hardware! + + Program in C! + </em> +</details> + +<hr /> + +<h1 id="conclusion">Conclusion</h1> + +<p>Learning C is a valuable experience and may be really worth it. If not as your +first language, then as second, third, fourth or whatever. There are +advantages, but (as always) also some disadvantages; at least trying won't hurt. +Give it a chance, who knows, you may truly get to like it.</p> + +<p>And don't believe people saying "C is dead". Love it or hate, C is still kicking +and the amount of crucial projects will keep it relevant for few next decades too.</p> + +<p> </p> + +<aside> + <p><strong>… a blot on the landscape</strong></p> + + <p>C was created in year 1972 on the foundation of B language, so over the years +it acquired some quirks (<code>memcpy()</code> is defined in string header!), some things +became obsolete, some useless and are kept only for compatibility with old code.</p> + + <p>A beginner is likely to burn a lot of time chasing down strange behavior caused +by memory corruption with no idea how to reason about, what may lead actually +big discouraged to programming in general. There is little to none mechanism +to prevent programmer from shooting themselves in the foot.</p> + + <p>It's also important to take into account that C is not the introduction to +Computer Science. Learning none of languages is. You need to study it properly +to get a true understanding of this vast field. If not formal education in +university, then online one will suffice too. The Internet is full of resources +(you may find a few on <a href="https://resources.joren.ga">my list</a>).</p> +</aside>JorengarenarHow comes that, after over half a century, C is still a relatively popular and widely used language when others have withered into obscurity? Why, over all this time, was nothing able to fully replace it? Why is it still taught in schools? \ No newline at end of file diff --git a/aliases b/aliases index 400c35ef..858bb5e0 100644 --- a/aliases +++ b/aliases @@ -568,7 +568,8 @@ alias solidproject="librewolf https://solidproject.org &" # split keyboard to eventually buy, learn to solder first alias aurora-sweep="librewolf https://splitkb.com/products/aurora-sweep &" - +# good shop for custom keyboards +alias beekeeb="librewolf https://shop.beekeeb.com/ &" # Bootcamps alias alchemy="librewolf https://www.alchemycodelab.com/ &" alias cirrorg="librewolf https://cirr.org/ &" # verify validity of bootcamp reviews