{"id":25056592,"url":"https://github.com/agvxov/cursed_c","last_synced_at":"2025-04-07T07:11:08.361Z","repository":{"id":203838061,"uuid":"696795101","full_name":"agvxov/cursed_c","owner":"agvxov","description":"An attempt to create the worst C program ever by repeatedly abusing obscure features. See c.c for the core code. Note that there were no version restraints imposed and extensions are also included.","archived":false,"fork":false,"pushed_at":"2024-12-19T21:40:32.000Z","size":455,"stargazers_count":106,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-31T05:09:09.966Z","etag":null,"topics":["c","dirty-code","educational","educational-project"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agvxov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-26T12:57:34.000Z","updated_at":"2025-03-26T03:48:10.000Z","dependencies_parsed_at":"2023-11-08T06:53:07.258Z","dependency_job_id":"df63fcba-3a80-487b-932a-fd92b66862b8","html_url":"https://github.com/agvxov/cursed_c","commit_stats":null,"previous_names":["agvxov/cursed_c"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agvxov%2Fcursed_c","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agvxov%2Fcursed_c/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agvxov%2Fcursed_c/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agvxov%2Fcursed_c/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agvxov","download_url":"https://codeload.github.com/agvxov/cursed_c/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247608151,"owners_count":20965952,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","dirty-code","educational","educational-project"],"created_at":"2025-02-06T13:34:05.325Z","updated_at":"2025-04-07T07:11:08.342Z","avatar_url":"https://github.com/agvxov.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cursed C\n\u003e An attempt to create the worst C program ever by repeatedly abusing obscure features.\nSee `c.c` for the core code.\nNote that there were no version restraints imposed and\nextensions are also included.\n\n---\n\n![demo](media/cursed_c_1.mini.jpeg)\n\n---\n\n## Rationale\n+ it was fun\n+ perhaps it will be educational for someone\n\n\n## Break down\n\n### File naming\n`c.c` is the least descriptive name imaginable to man.\nIt neither marks what project it belongs to or what purpose it has inside the project.\n\n### Trigraph characters\nThere used to be a time when there were computers widely in use\nwithout the ability to type some \"normal\" characters.\nSo alternative representations were added to replace them.\nBasically built-in macros.\nUnder `gcc` the `-trigraphs` flag is actually required to make them available.\n\nThe ones relevant here are:\n```\n??=    :    #\n??\u003c    :    {\n??\u003e    :    }\n```\n\nSo for example `??=define` really is just equivalent to `#define`.\n\n### \\$\\$\\$\nThe dollar sign is valid to be the first (and only the first) char of a symbol name.\nMy guess is that it is so for stubborn people\nwho prefer their variable names to start with a '$' as it has to in some other languages.\nPerhaps it's for ancient parsers/syntax highlighters?\nCreate an issue if you know better.\n\n### Concatenation macro operator\n`##` is a special operator available inside macro definitions.\nIt will literally glue together the arguments on its 2 sides.\nHistorically it has been used to generate symbol names.\n\n### include\\_next\nIncluding is surprisingly high-level with search paths and precedence.\nTurns out this happens to open a hole in functionality,\nwhich is otherwise absent from C.\n\nSo,\n`#include \u003cmyheader.h\u003e` will start trying to include the file 'myheader.h'\nsearching for in whatever directories the linker considers to contain system header files.\nThen,\n`#include \"myheader.h\"`\nstart from the current directory,\nbut falls back to the `\u003c\u003e` behavior.\nIn either case,\nwhatever is found first to satisfy the file name is taken.\nNow, what happens if we do not want the first?\nOr rather, we must have another.\n\nAs the GNU documentation explains it through an example,\nsay you wish to override a system header -say wrap it,\nbut your own header depends on the original one.\nStandard C provides no way to resolve the situation.\n\nFor this reason `#include_next` was added as a widely accepted extension,\nwhich excludes the current path from the list of searchable paths\nto prohibit recursive inclusion.\n\n### iso646.h\nFrom what I've seen,\nthis perfectly standard header that tends to be relatively little known.\nIf you know C++ and about its keyword operators,\nthen this is what defines their equivalents in C.\nE.g `and`, `or`, etc.\n\nLater down it's abused to get the address of `ű`:\n```C++\nbitand ű\n```\nWhere -you guessed it- \n`bitand` is just macrod to be `\u0026` at the end of the day.\n\nTo make it extra fitting, it uses the worst imaginable formatting,\nwhich is -fun fact- unreproducible with '\u003c\u003e's as the preprocessor '\"\"'s\njust so happens to use the exact grammar as fully featured C string literals do.\nLucky us, every '\u003c\u003e' include is a valid '\"\"' include with only a slight compile overhead\n(as the local include is path is checked first, then the system headers).\n\n### \\_Decimal32\nIt's exactly what it sounds like,\na decimal fraction available in C.\nHere, as a GNU extension.\n\n### Dot dot dot\nNot nearly as obscure as the rest, but worth including.\n`...` signals to the compiler that any number of values may be pushed into the stack\non any call to this function.\nNormally `stdarg.h` and it's va\\_list (\"Variable Argument LIST\") would be used or\nsome pointer magic applied by hand to read said values,\nbut here they are just left unused.\n\nThe most famous function using this feature has to be `printf`.\nIn glibc it's defined as:\n```C\nextern int printf (const char *__restrict __format, ...);\n```\nThat's why it can handle both`printf(\"%d\", 1)` and `printf(\"%d %d\", 1, 2)`.\n\n### const const const\nThe specifier `const` turns out to be infinitely stackable.\nIn fact, it can be applied to the wrong spot too.\n\n```C\nconst const int i;\n```\nReduces to:\n```C\nconst int i;\n```\n\nThis program makes both the pointed value and the pointer constant,\nthen reiterates it a few times for good measure.\n\nWith a bit of simplification:\n```C\n   const char const * const;\n//   ^          ^       ^\n//   |          |       |\n//   |          |  constant pointer\n//   |          |\n//   |  const... air? for no effect\n//   |\n// constant character value\n```\n\n### Naming\nHaving multi-char long variable names is bloat.\nNaming everything a single letter is the way of the warrior.\n#### Ű\n'ű' is letter in the Hungarian alphabet.\nThe reason it was chosen is because it is non-ascii.\nDon't like it?\nPerhaps switch it out for a '😁',\nwhich is also valid due to the same mechanic.\n\n### Haskel style semi-colons\nI guess it's self-evident that C being whitespace agnostic,\nstarting every line with ';' instead of closing them with it,\nis valid,\nhowever it's a rarely thought about possibility.\nAlso, semi-colons are stackable.\n\n**Pro-tip:** the next time someone proposes indenting with spaces to you,\nsuggest indenting with semi-colons.\n\n### 'a' array\nWhen accessing an array element,\n`a[n]` is equivalent to `\u0026a + n`.\nNote that the address is taken only figuratively,\nthe array `a` decays to a pointer to the first element,\nso the more scientific notation is `*(a + n)`\n#### Smiles\nLike trigraphs, but they are too hard to type? Digraphs are for you! :\u003e\n```\n%:    :    #\n\u003c%    :    {\n%\u003e    :    }\n\u003c:    :    [\n:\u003e    :    ]\n```\n#### Reverse reference\n```C\n-1[$a];\n```\nNo, we are not trying to access the `$a`th element of `-1`.\nAddition commutative, hence `*(a + n)` == `*(n + a)`.\n\nThe above evaluates exactly like:\n```C\n$a[-1];\n```\n#### Negative index\nSince `a + (-n)` is `a - n`,\nit just werks™.\n\n### Puts call\nPerhaps you noticed `#include \u003cstdio.h\u003e` missing.\nDon't worry,\nthe compiler will implicitly handle it for us!\n\n### Return\nRelative to Assembly, C is high-level.\nAnd in many cases,\nfor Assembly programmers,\nthe `return` statement high-level enough to be considered many ways similar to a function.\nFor this reason they may stick to the following syntax:\n```C\nreturn(0);\n```\n\n### END comments\nLarge blocks being closed with their type/name explicitly mentioned\ntend to be more readable than otherwise.\nWith C however a nice balance of size is attainable.\nOvershoot a bit and you get people pretending comments are significant.\nWait 30 years and -looking for a more radical solution-\nthey form a cult around DRY.\n\n### Attributes\nAttributes tend to be left out from textbooks,\nbut they are extremely cool.\nThey provide ways to both aid the compiler (or make it shut up)\nand make code self-documenting.\n\nToo bad that C initially botched the syntax.\nConsider the following:\n\nBoth of these specify that `func` will never return.\n\nC:\n```C\n__attribute__((noreturn))\n```\nC++:\n```C++\n[[ noreturn ]]\n```\n\nBut good news!\nWith C23,\nC++ style attributes are being introduced.\n\nWhat better way to celebrate this,\nthan to use all syntaxes possible at the same time?\n\n### F == F\nAs unreadable the code might be,\nsurely,\nthis line should prematurely terminate our horrors, right?\n```C\nif (F == F) { return 1; }\n```\nNo, you see, because floats.\nThis,\ntechnically,\nhas little to do with C.\nIEEE 754,\nin a round about way,\nspecifies that comparisons with NaN is false.\nThis extends to `NaN == NaN` too.\nC simply implements it.\n\nAnd,\nthanks to the dubious operation of zero divided by zero,\nused for defining `F`,\nresulting in NaN,\nwe are able to proceed to the rest of the mayhem.\n\n### Google?\nGoogle.\n```C\n; https://google.com\n```\nURLs happen to be valid C.\nMore precisely,\nthey are -due to pure chance- a label plus a comment.\nYou can only have one per protocol per function,\nchoose wisely.\n\nThe address was chosen in particular,\nbecause hard coding google endpoints into source is as evil\n(or rather, no longer \"don't be evil\")\nas it gets.\n\n### ?\nIf one asks a C programmer\n\"can the ternary operator be used to conditionally declare a (const) variable\"\neven if he never needed to use it,\nhe will instinctively answer yes.\nYet,\nno one seems to ever state this -truth be told, rare times, but- very useful feature.\nInstead, its main purpose is to serve as premature formatting.\n\nWhile the functionality is not cursed,\nthe poor operator itself seems to be.\n\n### Nested functions\nYou would be surprised to know how popular these things used to be in the past.\nAnd I'm not talking about C in particular.\n\n\u003e In the case of nested procedures, the scope rules permit, for example, the definition\n\u003e of a procedure to include the definition of subsidiary procedures without concern for\n\u003e interference with other global procedures. This capability facilitates writing pro-\n\u003e cedures and often simplifies their usage.\n\u003e\n\u003e -- David R. Hanson; Is Block Structure Necessary? (1981)\n\nYet,\nthey have fallen out from the public's taste so much that C++ disallows it.\nNested classes seem to be looked down upon too now days,\neven in bloody Java tutorials where providing a single file would\nbe so damn much clearer and easier,\nbut I digress.\n\n### Code in switch\nA switch statement is just a fancy code block with a bunch of labels and a jump-table.\nSo, in our:\n```C\n    switch (h) {\n        int a = 89;\n        default: break;\n    }\n```\nexpression,\nthe available value mappings (none) are compared to h,\nthen execution jumps to `default` as no match was found.\nNow the question becomes:\nhow is that `a` is defined to 89?\nEasy. It's not.\n`a` gets defined, but its assignment is skipped.\nIt's because variable declarations always result in allocations at the start of the scope,\nno further questions asked.\nFor all the compiler cares,\n`int a;` might as well have been written under `default:`.\nHowever, the value copy is skipped.\n\n### String literal concatenation\nAdjacent string literals are always (compile time) concatenated.\nTherefore:\n```C\n\"Make it stop, cruel\" \" \" \"w\" \"o\" \"r\" \"l\" \"d\" \"!\"\n```\nCostlessly becomes:\n```C\n\"Make it stop, cruel world!\"\n```\nWhy is it cursed? Ask who ever does this:\n```C\nputs(\"Message line 1\");\nputs(\"Message line 2\");\n```\nInstead of:\n```C\nputs(\"Message line 1\\n\"\n     \"Message line 2\");\n```\n\n### Literal pointer arithmetics\nA string literal \"decays\" into a const char pointer,\ntherefore `puts(\"//Please!\" + 2)` is just the heretic way of saying:\n```C\nconst char * s = \"//Please!\";\nputs(s + 2);\n```\n\n### Batch assignment\nThe assignment operator is not particularly \"special\" in C.\nIt does the actual value copying,\nbut then plainly \"returns\" a value of its own.\nWhich happens to be defined as the one assigned.\n\n\"Tricks\" like this and such:\n```C\n    do {\n        // ...\n    } while(i = fun());\n```\ntend to be pretty neat.\n\nHowever,\nfor wholeness,\nit stacks.\n```C\ni = h = j = k\n```\nIs evaluated right to left.\nI.e. it becomes \"assign k to j; assign j to h; assign h to i;\".\nSo what value does `i` hold after the operation?\nNo one knows, since `k` was never initialized!\n\n### Comma operator\nThe comma operator evaluates the expressions on both sides,\nthen returns the value returned by the right-hand side.\nAgain, it's stackable.\n\nThis -similar to the wise usage of assignments,-\nopens a little door for playing with loop conditions.\n```C\ndo {\n    // ...\n} while((fun(\u0026a), a));\n```\n\n\nBut also, if you ever wanted to make semi-colons jealous to make them love you more,\nhere is your chance.\n```C\nfun1(), fun2(), fun3(), fun4()\n```\n\n\u003e Do not use the comma operator.\n\u003e \n\u003e Do not use the comma operator.\n\u003e \n\u003e Do not use the comma operator.\n\u003e \n\u003e [...]\n\u003e \n\u003e Do not use the comma operator.\n\u003e \n\u003e Do not use the comma operator.\n\u003e \n\u003e Do not use the comma operator.\n\u003e \n\u003e -- Repeater, https://cplusplus.com/forum/beginner/272615/ \n\n### K\u0026R arguments\nThe language design of C is truly genius.\nBrian Kernighan and Dennis Ritchie got so many things perfectly right.\nOne clear exception is their original function declaration syntax.\nNot that it doesn't make sense or does not have historical reasons,\nbut damn is it to ugly and confusing.\n\nA reasonably cleaned up version of our `main()` would look like this:\n```C\nvoid main(argc, argv, envp)\nint argc;\nchar * * argv;\nchar * * envp;\n{ ; }\n```\nWhere our parameters are named first,\nthen their type is specified.\nThis original way,\nused to be the only way to do it.\nIt may look like absolutely useless typing at first,\nbut there are a few things to consider.\n\n1. it roots from B syntax,\nwhich is typeless:\n```B\nmain(argc, argv, envp) {\n    ;\n}\n```\n\n2. One doesn't specify the types of your arguments\nuntil the function definition:\n```C\n\nvoid main(argc, argv, envp);\n\nvoid main(argc, argv, envp)\nchar * * argv;\nint argc;\nchar * * envp;\n{ ; }\n```\nWhich implies that\na) you don't have to keep your declarations and definitions in sync\nb) calls can compile without type checking\n\n3. It blends with other syntax rules, allowing this:\n```C\nvoid main(argc, argv, envp)\nchar * * argv;\nint argc;\nchar * * envp;\n{ ; }\n```\nAnd this:\n```C\nvoid main(argc, argv, envp)\nint argc;\nchar * * argv, * * envp;\n{ ; }\n```\n\n### I would like to declare the type of nothing\n```C\ng() int; int; { int; }\n```\nGCC allows you have a typename on its own line.\nNot even a warning in sight.\n\nWhy does it allow it? Good question.\n\n### h.h\nAs you know, this project compiles under gcc,\nStill, catting out h.h should make you raise your eyebrow.\n```C\n#error\n```\nIts impossible that that's the actual header included and\nI must have messed with the compiler, right?\nWell, yes, but not the way you think.\nIf you wanted to prove me guilty of manipulating the include path\nby inspecting the build script,\nyou could not:\n```sh\ngcc c.c -trigraphs -Wall -Wextra -Wpedantic\n```\nTho, there is also something suspicious going on with `h.h`:\n```sh\ngcc detention/h.h -o ./h.h.gch\n```\nWhere the contents of `detention/h.h` seems like something that would translate.\nThat is a good lead, however `detention/` is hardly a standard folder to override with.\n\nThe solution is in the `.gch` extension as in \"GNU Compiled Header\".\nIts what it sounds like, a header processed by gcc.\nAfter the header is compiled once,\nits code can be included in multiple source files without it being reprocessed.\nThis trick can significantly speed up compile times.\nWell, when it works that is.\n\nFor example if it was 1 line lower in the source,\nit would make the operation `#error` out.\nThe documentation lists 10 reasons why a compiled header could be rejected\nand `iso646.h` breaks *one* of those.\nConsidering that's a standard header with around a dozen defines,\nyou can guess how stable it is.\nNot to mention it fails silently.\ngcc provides no feedback whether it did or did not use a compiled header,\nlet alone why.\nPessimism aside,\ncompiled headers are great as long as you can make sure\nthey are at the top of the source (with an `-include` perhaps)\nand seem way more reliable with clang (because they have their own version too).\n\n### Empty parenthesis \nHow would you declare a function with no parameters?\nIf you answered the following:\n```C\nf();\n```\nThen you just found a footgun!\nThat actually signals how the function takes...\nwell,\nwe don't know what it takes, so better allow anything!\nTake a look at `g`:\n```C\ng() int; int; { int; }\n```\nIgnoring those `int`s,\none could assume it takes 0 arguments,\nyet if you glimpse at how it's called:\n```C\ng(i = h = j = k)\n```\nYou will see how passing one int is valid, in fact, it doesn't even warrant a warning!\nThis,\nagain routes from the K\u0026R style,\nwhere as established before,\narguments where not expected to be type checked.\n\nSooo,\nis `g()` equivalent to `g(...)`?\nNo!\nFor one,\n`...` required a named argument before itself until C2X.\nHowever,\nin the case of `g()` the compiler not required to perform type promotions.\nAlso,\nthe generated assembly is... strange.\nThat's what `tool/g().c` and `tool/g(...).c` are here for.\nHere is the relevant part of their disassembly:\n```Asm\n// @BAKE gcc -g -O0 \"$@\" -o \"$*\"                                |  // @BAKE gcc -g -O0 \"$@\" -o \"$*\" -Wall -Wpedantic\n\ng() {                                                           |  g(...) {\n    1129:       f3 0f 1e fa             endbr64                        1129:       f3 0f 1e fa             endbr64\n    112d:       55                      push   %rbp                    112d:       55                      push   %rbp\n    112e:       48 89 e5                mov    %rsp,%rbp               112e:       48 89 e5                mov    %rsp,%rbp\n                                                                \u003e      1131:       48 83 ec 38             sub    $0x38,%rsp\n                                                                \u003e      1135:       48 89 bd 50 ff ff ff    mov    %rdi,-0xb0(%rbp)\n                                                                \u003e      113c:       48 89 b5 58 ff ff ff    mov    %rsi,-0xa8(%rbp)\n                                                                \u003e      1143:       48 89 95 60 ff ff ff    mov    %rdx,-0xa0(%rbp)\n                                                                \u003e      114a:       48 89 8d 68 ff ff ff    mov    %rcx,-0x98(%rbp)\n                                                                \u003e      1151:       4c 89 85 70 ff ff ff    mov    %r8,-0x90(%rbp)\n                                                                \u003e      1158:       4c 89 8d 78 ff ff ff    mov    %r9,-0x88(%rbp)\n                                                                \u003e      115f:       84 c0                   test   %al,%al\n                                                                \u003e      1161:       74 20                   je     1183 \u003cg+0x5a\u003e\n                                                                \u003e      1163:       0f 29 45 80             movaps %xmm0,-0x80(%rbp\n                                                                \u003e      1167:       0f 29 4d 90             movaps %xmm1,-0x70(%rbp\n                                                                \u003e      116b:       0f 29 55 a0             movaps %xmm2,-0x60(%rbp\n                                                                \u003e      116f:       0f 29 5d b0             movaps %xmm3,-0x50(%rbp\n                                                                \u003e      1173:       0f 29 65 c0             movaps %xmm4,-0x40(%rbp\n                                                                \u003e      1177:       0f 29 6d d0             movaps %xmm5,-0x30(%rbp\n                                                                \u003e      117b:       0f 29 75 e0             movaps %xmm6,-0x20(%rbp\n                                                                \u003e      117f:       0f 29 7d f0             movaps %xmm7,-0x10(%rbp\n        return 2;                                                          return 2;\n    1131:       b8 02 00 00 00          mov    $0x2,%eax        |      1183:       b8 02 00 00 00          mov    $0x2,%eax\n}                                                                  }\n    1136:       5d                      pop    %rbp             |      1188:       c9                      leave\n    1137:       c3                      ret                     |      1189:       c3                      ret\n```\nOn the right side,\n`g(...)` actually reads a bunch of values from the stack into registers.\nWhat I *think* is happening is that the compiler would really like to optimize\narguments being read from the stack directly,\nbut since -O0 was on,\nit was not allowed to make any assumptions about,\nhow `g` will be called,\nhence it loads as much as it can.\n\n(If you know better, please correct me!)\n\n### Duff()\nAs you can see `case` statements work inside nested blocks of the corresponding `switch`.\nWhich is funny by itself, but what that allows us to do is something called a \"Duff's Device\".\nThis allows us to force loop unrolling within the bounds of C.\n\nI can explain it best with an incremental example. Consider:\n```C\ndo {\n    perform_stuff();\n} while (counter++ \u003c repeat_count);\n```\nHere,\nafter every call to `perform_stuff()` we have to perform a jump instruction\nto the top of the loop for every repetition.\nWith the standards of modern software,\nthe cost is small,\nhowever there are circumstances where it could be a legitimate performance concern.\nAn optimization would be:\n```C\ndo {\n    perform_stuff();\n    perform_stuff();\n    perform_stuff();\n    perform_stuff();\n    counter += 4;\n} while (counter \u003c repeat_count);\n```\nNow, we only need a jump after every 4 calls!\nGreat,\nexcept if `repeat_count` is not a multiple of 4,\nwe actually call `perform_stuff()` the wrong number of times...\nThis is where Duff's Device comes into the picture.\n```C\nswitch (repeat_count % 4) {\n    case 0: do { perform_stuff(); counter++;\n    case 1:      perform_stuff(); counter++;\n    case 2:      perform_stuff(); counter++;\n    case 3:      perform_stuff(); counter++;\n    } while (counter \u003c repeat_count);\n}\n```\nThe switch \"eats away\" some number of calls,\nguaranteeing `(repeat_count - count) % 4 == 0` and\n`peform_stuff()` being called the desired number of times.\n(Unless it was 0, that's an edge case we do not account for in the example for simplicity.)\nIn our `duff()` we apply this trick to copying a string.\n\nIt should also be mentioned,\nthat due to modern compiler optimizations,\nDuff's Device may or may not result in actual performance gains\n([see here](https://belaycpp.com/2021/11/18/duffs-device-in-2021/)).\nYou may read Duff's own thoughts regarding it\n[here](http://doc.cat-v.org/bell_labs/duffs_device).\n\n### \\_sum(int argc, ...)\nBack to variadic functions and their quirks.\nWho cares if they nuke type safety?\nLet's talk about the real problem: ergonomics.\n\nAny variadic function has to have some way to tell how many arguments it was given.\nIn practice this boils down to one of the following techniques:\n+ pass the number of extra arguments as a named argument\n+ encode the number of arguments in a named argument (e.g. format string)\n+ choose a termination value for the extra arguments (e.g `NULL`, passed as the last argument)\n\nSometimes -when trying to create comfortable interfaces- the first option seems perfect,\nif not for passing this count by hand.\n\nThing is, the preprocessor can save our day.\nTake a look inside `auto_vararg.h`.\n\nMacros can be variadic too.\n`__VA_ARGS__`  is a standard macro, it simply expands to the variadic arguments.\n\n`PP_128TH_ARG` always expands to its 128th argument.\n\n`PP_RSEQ_N` expands to 128 numbers in descending order, 0 inclusive.\n\nIf we pass `PP_RSEQ_N` to `PP_128TH_ARG` it will return 0 to us.\nIf we were to place exactly one argument before `PP_RSEQ_N`,\nall of its values would be shifted to the right,\nresulting in `1` becoming the 128th argument of `PP_128TH_ARG`.\nMore generally, passing N arguments before `PP_RSEQ_N` will offset it by N,\nshifting the correct value to the 128th argument of `PP_128TH_ARG`.\n\nIn effect, we have just automated passing the argument count!\n\nArgument counter hack credits:\n+ [https://stackoverflow.com/a/35693080](https://stackoverflow.com/a/35693080)\n+ [https://stackoverflow.com/a/26408195](https://stackoverflow.com/a/26408195)\n+ [https://stackoverflow.com/a/2124385](https://stackoverflow.com/a/2124385)\n\n---\n\n## Challenge\n+ Try to make the project worse\n### Completionists\n* SurmanPP\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagvxov%2Fcursed_c","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagvxov%2Fcursed_c","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagvxov%2Fcursed_c/lists"}