[{"content":" No problem can be solved at the same level of thinking that created it.1 \u0026mdash; \u0026ldquo;Albert Einstein\u0026rdquo;\nConsistency Challenge The first time I ran into X Macros was while debugging an out-of-bounds access issue.\nHere is a simplified example:\n// a.h typedef enum { SYS_OK, SYS_ERR_TIMEOUT, SYS_ERR_BUSY, SYS_ERR_INVALID_ARG, SYS_ERR_NOT_FOUND } SysState; // a.c const char *state_desc[] = { [SYS_OK] = \u0026#34;System OK\u0026#34;, [SYS_ERR_TIMEOUT] = \u0026#34;Timeout\u0026#34;, [SYS_ERR_BUSY] = \u0026#34;System Busy\u0026#34;, [SYS_ERR_INVALID_ARG] = \u0026#34;Invalid Argument\u0026#34; // SYS_ERR_NOT_FOUND is missing here }; int main() { printf(\u0026#34;State = %s\\n\u0026#34;, state_desc[SYS_ERR_NOT_FOUND]); } The issue is easy to spot: SYS_ERR_NOT_FOUND was added to the enum, but the string table was not updated.\nWhen the program evaluates state_desc[SYS_ERR_NOT_FOUND], it reads past the end of the array and eventually crashes.\nOf course, we could fix this by adding the missing entry to the string table. But that only fixes this specific bug — it does not prevent the same type of problem from happening again.\nThe underlying issue is that we are maintaining two pieces of information that must always stay consistent:\nthe enum definition the string table As long as these are maintained separately and rely on manual synchronization, mistakes like this are inevitable.\nWhat we really need is a way to eliminate this class of problems entirely.\nX Macros While looking for a solution, I came across an article by Randy Meyers published in Dr. Dobb\u0026rsquo;s Journal titled The New C: X Macros 2. The article introduces a technique that uses the C preprocessor to generate code from a single data definition.\nThis technique is commonly known as X Macros.\nThe idea is simple: maintain a single data list, and generate the necessary code structures by redefining a macro.\nLet\u0026rsquo;s modify the previous example to see how this works.\nFirst, define a Single source of truth:\n#define SYS_STATE_LIST \\ X(SYS_OK, \u0026#34;System OK\u0026#34;) \\ X(SYS_ERR_TIMEOUT, \u0026#34;Timeout\u0026#34;) \\ X(SYS_ERR_BUSY, \u0026#34;System Busy\u0026#34;) \\ X(SYS_ERR_INVALID_ARG, \u0026#34;Invalid Argument\u0026#34;) \\ X(SYS_ERR_NOT_FOUND, \u0026#34;Not Found\u0026#34;) This list becomes the master definition of our data. Each entry is wrapped inside a placeholder macro X().\nThe name X is simply a convention. It has no special meaning and can be replaced with any name.\nNext, we define the macro X to generate the enum:\n#define X(name, desc) name, typedef enum { SYS_STATE_LIST } SysState; #undef X Then we redefine X so that the same list generates the string table:\n#define X(name, desc) [name] = desc, const char *state_desc[] = { SYS_STATE_LIST }; #undef X If you come from dynamic languages such as Python or Java, this might look somewhat like a lightweight form of reflection.\nX Macros gather scattered information into a single data list. By redefining and undefining X (#undef), the same data can be injected into multiple code templates. Adding, removing, or reordering entries will not introduce inconsistencies.\nThis technique works well in many situations where related data must stay synchronized, for example:\nManaging error codes, states, or event types together with their descriptions Generating command tables or protocol definitions Serialization and deserialization Configuration data initialization and access code generating Advanced Notes X Macros are powerful, but they do come with trade-offs. Macro-heavy code can reduce readability and make debugging more difficult.\nSome practical tips:\nImprove readability: Andrew Lucas suggests passing the macro X as a parameter to the data list to make the structure clearer 3.\nLarge data sets: If the list becomes very long, you may hit compiler line-length limits. Randy Meyers recommends placing the list in a separate.def or .h file and using #include to reuse it.\nInspect preprocessed output: You can use gcc -E to view the expanded source code. Many modern IDEs with language servers can also show this.\nTeam communication: Not everyone is familiar with this technique. Good comments and documentation help avoid confusion.\nUse it sparingly: Like most macro tricks, X Macros should be used thoughtfully rather than everywhere.\nSummary X Macros are essentially a lightweight metaprogramming technique built on top of the C/C++ preprocessor. In environments without reflection or code generation tools, they provide a practical way to keep related definitions synchronized.\nBy maintaining a Single Source of Truth and generating code through macro expansion, X Macros eliminate the risk of inconsistent duplicated definitions.\nThe idea dates back to assembly programming in the 1960s. Even today, whenever large amounts of structured data need to remain consistent, it remains a surprisingly useful technique — and a valuable tool in the C/C++ programmer\u0026rsquo;s toolbox.\nAI translated. I discovered this link when I tried to find the source of this quote:https://www.quora.com/Einstein-said-that-you-cannot-solve-a-problem-from-the-same-level-of-consciousness-that-created-it-What-did-he-mean-with-it-Can-you-use-a-concrete-example\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nRandy Meyers. \u0026ldquo;The New C: X macros\u0026rdquo;, Dr.Dobb\u0026rsquo;s 2001, accessible at:https://jacobfilipp.com/DrDobbs/articles/CUJ/2001/0105/meyers/meyers.htm\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nAndrew Lucas. \u0026ldquo;Reduce C-language coding errors with X macros\u0026rdquo;, Embedded.com, 2013.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","permalink":"https://victorhge.github.io/posts/xmacro/","summary":"\u003cblockquote\u003e\n\u003cp\u003eNo problem can be solved at the same level of thinking that created it.\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e\n\u0026mdash; \u0026ldquo;Albert Einstein\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"consistency-challenge\"\u003eConsistency Challenge\u003c/h2\u003e\n\u003cp\u003eThe first time I ran into X Macros was while debugging an out-of-bounds access issue.\u003c/p\u003e\n\u003cp\u003eHere is a simplified example:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// a.h\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etypedef\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eenum\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    SYS_OK,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    SYS_ERR_TIMEOUT,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    SYS_ERR_BUSY,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    SYS_ERR_INVALID_ARG,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    SYS_ERR_NOT_FOUND\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e} SysState;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// a.c\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003estate_desc[] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    [SYS_OK] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;System OK\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    [SYS_ERR_TIMEOUT] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Timeout\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    [SYS_ERR_BUSY] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;System Busy\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    [SYS_ERR_INVALID_ARG] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Invalid Argument\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// SYS_ERR_NOT_FOUND is missing here\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e};\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;State = %s\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, state_desc[SYS_ERR_NOT_FOUND]);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe issue is easy to spot: \u003ccode\u003eSYS_ERR_NOT_FOUND\u003c/code\u003e was added to the enum,\nbut the string table was not updated.\u003c/p\u003e","title":"X Macros"},{"content":"I recently set up a small blog on GitHub Pages. It was almost effortless—pick a theme, tweak a few parameters, and the site is live. Since I was already tinkering, I decided to make it bilingual. Every post now starts in Chinese, then gets translated into English with the help of an AI model.\nThe quality of machine translation today is, frankly, impressive. Most of the time, a light round of editing is enough before publishing.\nAnd yet, something never quite sits right.\nThe sentences are correct. The meaning is intact. But the text feels… distant. As if there’s a thin layer between the words and the reader—hard to name, harder to ignore.\nThat unease sharpened one day when I worked on a longer piece. The translated version felt particularly off. So I did a side-by-side comparison of several posts, Chinese against English. The result was unsettling—like catching your reflection in a mirror and realizing, for a split second, that it isn’t you.\nIt brought to mind an old line of poetry about crossing a threshold and becoming a stranger ever after:\nOnce you enter the noble\u0026rsquo;s gate, it\u0026rsquo;s as deep as th sea; from then on, the former love is but a stranger.\nThe problem, I realized, wasn’t the translation. It was the Chinese.\nFor years, I’ve worked in environments where English is the default. Emails, documentation, code, comments—everything happens in English. Chinese never disappeared, but it retreated into casual conversation: chats, messages, everyday exchanges.\nLooking back at my recent blog posts, I noticed something uncomfortable. The Chinese and the English versions aligned almost word for word. On the surface, they were written in Chinese. But structurally, they followed English logic so closely that they could be mapped directly onto each other.\nSomewhere along the way, I had developed a habit. Whenever I “write,” my thoughts take a detour through English before landing in Chinese. What I had taken for Chinese writing was, in fact, English composition wearing Chinese characters.\nNo wonder it reads like a translation.\nI suspect I’m not alone in this.\nFor many bilingual speakers, written expression gradually leans toward English. Chinese recedes into speech, rarely called upon for sustained, complex thought. And like any skill left unused, it begins to dull.\nYou don’t notice it at first. Only when you try to write something serious do you realize the words no longer come as easily.\nUse it, or lose it.\nIn an odd way, this blog has been a wake-up call. It forced me to see the problem clearly. And the solution, though simple, is not easy: start writing in Chinese again—deliberately, persistently, and with attention.\nAs I write this, I find myself examining each sentence as it forms:\nCould this be translated directly into English?\nIf the answer is yes, something is probably off.\n","permalink":"https://victorhge.github.io/posts/translationese/","summary":"\u003cp\u003eI recently set up a small blog on GitHub Pages. It was almost effortless—pick a\ntheme, tweak a few parameters, and the site is live. Since I was already\ntinkering, I decided to make it bilingual. Every post now starts in Chinese,\nthen gets translated into English with the help of an AI model.\u003c/p\u003e\n\u003cp\u003eThe quality of machine translation today is, frankly, impressive. Most of the\ntime, a light round of editing is enough before publishing.\u003c/p\u003e","title":"Translationese"},{"content":"Emacs comes with numerous default keybindings, which inevitably conflict with system-level shortcuts. For Emacs beginners, resolving these conflicts can be a significant challenge.\nOne of the most common conflicts is with the command set-mark-command, which default binding is C-SPC~(Ctrl+Space)1. On Windows, Ctrl+Space is often used to toggle between English and Chinese input methods, which can makeCtrl+Space unusable for marking in Emacs.\nTo resolve this issue, you can either use the alternative binding forset-mark-command, C-@, or disable the Ctrl+Space functionality in Windows. Additionally, since the spacebar can be operated easily with either thumb, there is a \u0026ldquo;third option\u0026rdquo;: you can configure the Ctrl+Space so that one side Ctrl+Space is reserved for Windows, while the other side Ctrl+Space is available for Emacs or other applications. This is the solution I adopted because it allows me to maintain my habit of using both thumbs for operation.\nIn the latest version of Windows 11, you can achieve this as follows:\nGo to Settings \u0026gt; Time \u0026amp; Language \u0026gt; Language \u0026amp; region \u0026gt; Options \u0026gt; Microsoft Pinyin \u0026gt; Keys, and uncheck the Ctrl + Space box while leaving Shift checked.\nOpen PowerToys (install it if you don\u0026rsquo;t already have it). In the Keyboard Manager section, add a key remapping: map Ctrl(Left) + Space to Shift orWin(Left) + Space.\nFor older versions of Windows, where there\u0026rsquo;s a UI bug preventing such changes 2, you can solve this by manually editing the registry:\nNavigate to HKEY_CURRENT_USER\\Control Panel\\Input Method\\Hot Keys\\00000010. Modify the value of Key Modifiers to 02 80 00 00, or 02 40 00 00 3. If you want to apply this change for all new users, make the same modification under HKEY_USERS\\.DEFAULT\\Control Panel\\Input Method\\Hot Keys\\00000010. After making these changes, restart your computer to take effect.\nIt seems that only Ctrl+Space can be “split,” as other key combinations are naturally easier to reach with one hand. For example, Ctrl+a inherently impliesRight Ctrl+a.\nEmacs uses unique convention for keybinngs, where C-SPC is shorthand forCtrl+Space. This article adopts the common convention for now.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nhttps://superuser.com/questions/327479/ctrl-space-always-toggles-chinese-ime-windows-7\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n02 indicates Ctrl, 80 indicates the left side, and 40 indicates the right side.https://learn.microsoft.com/en-us/windows/win32/tsf/tf-mod--constants\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","permalink":"https://victorhge.github.io/posts/ctrl_space/","summary":"\u003cp\u003eEmacs comes with numerous default keybindings, which inevitably conflict with\nsystem-level shortcuts.  For Emacs beginners, resolving these conflicts can be a\nsignificant challenge.\u003c/p\u003e\n\u003cp\u003eOne of the most common conflicts is with the command \u003ccode\u003eset-mark-command\u003c/code\u003e, which\ndefault binding is \u003ccode\u003eC-SPC~(Ctrl+Space)\u003c/code\u003e\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e.  On Windows, \u003ccode\u003eCtrl+Space\u003c/code\u003e is\noften used to toggle between English and Chinese input methods, which can make\u003ccode\u003eCtrl+Space\u003c/code\u003e unusable for marking in Emacs.\u003c/p\u003e\n\u003cp\u003eTo resolve this issue, you can either use the alternative binding for\u003ccode\u003eset-mark-command\u003c/code\u003e, \u003ccode\u003eC-@\u003c/code\u003e, or disable the \u003ccode\u003eCtrl+Space\u003c/code\u003e functionality in\nWindows.  Additionally, since the spacebar can\nbe operated easily with either thumb, there is a \u0026ldquo;third option\u0026rdquo;: you can\nconfigure the \u003ccode\u003eCtrl+Space\u003c/code\u003e so that one side \u003ccode\u003eCtrl+Space\u003c/code\u003e is reserved for\nWindows, while the other side \u003ccode\u003eCtrl+Space\u003c/code\u003e is available for Emacs or other\napplications.  This is the solution I adopted because it allows me to\nmaintain my habit of using both thumbs for operation.\u003c/p\u003e","title":"Splitting Ctrl+Space"},{"content":" This is an essential configuration for all the computers I use, all because of Emacs.\nEmacs was originally developed as a set of macros for the TECO editor (Editing MACroS). At that time, the keyboard layout used by the developers placed the Ctrl key next to the spacebar1, making it convenient for operation with the thumbs. For some reason, standard keyboards that became widespread with personal computers moved the Ctrl key to the outermost position, which forces usage with the pinky finger. This design easily fatigues the pinky.\nTherefore, I choose to swap the Ctrl and Alt keys, returning the Ctrl key to a thumb-operable position, alleviating pinky strain and significantly improving efficiency.\nHere’s how I do it:\nWindows: Using SharpKeys for key remapping. Linux (GNOME desktop): GNOME Tweak Tool makes this easy to configure2. This is a \u0026ldquo;once-you-use-it-you-can\u0026rsquo;t-go-back\u0026rdquo; configuration. It also has a\u0026lsquo;hidden feature\u0026rsquo; - driving others crazy when they try to use my keyboard.\nKnight Keyboard http://xahlee.info/kbd/knight_keyboard.html\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nGNOME Treak Tool https://askubuntu.com/questions/885045/how-to-swap-ctrl-and-alt-keys-in-ubuntu-16-04/885047\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","permalink":"https://victorhge.github.io/posts/swap_ctrl_alt/","summary":"\u003cfigure\u003e\n    \u003cimg loading=\"lazy\" src=\"/ox-hugo/lisp-machine-keyboard-2.jpg\"/\u003e \n\u003c/figure\u003e\n\n\u003cp\u003eThis is an essential configuration for all the computers I use, all because of\nEmacs.\u003c/p\u003e\n\u003cp\u003eEmacs was originally developed as a set of macros for the TECO editor (\u003ca href=\"https://blog.djmnet.org/2008/08/05/origin-of-emacs/\"\u003eEditing\nMACroS\u003c/a\u003e). At that time, the keyboard layout used by the developers placed the\nCtrl key next to the spacebar\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e, making it convenient for operation with\nthe thumbs. For some reason, standard keyboards that became widespread with\npersonal computers moved the Ctrl key to the outermost position, which forces\nusage with the pinky finger. This design easily fatigues the pinky.\u003c/p\u003e","title":"Swapping Ctrl and Alt Keys"}]