<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>C/C++ on Illusion and Trifle</title><link>https://victorhge.github.io/tags/c/c++/</link><description>Recent content in C/C++ on Illusion and Trifle</description><generator>Hugo -- 0.156.0</generator><language>en</language><copyright>Source code here, licensed under GPLv3 ·</copyright><lastBuildDate>Thu, 12 Mar 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://victorhge.github.io/tags/c/c++/index.xml" rel="self" type="application/rss+xml"/><item><title>X Macros</title><link>https://victorhge.github.io/posts/xmacro/</link><pubDate>Thu, 12 Mar 2026 00:00:00 +0800</pubDate><guid>https://victorhge.github.io/posts/xmacro/</guid><description>A simple technique for solving consistency problems in C/C++ projects</description><content:encoded><![CDATA[<blockquote>
<p>No problem can be solved at the same level of thinking that created it.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>
&mdash; &ldquo;Albert Einstein&rdquo;</p>
</blockquote>
<h2 id="consistency-challenge">Consistency Challenge</h2>
<p>The first time I ran into X Macros was while debugging an out-of-bounds access issue.</p>
<p>Here is a simplified example:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-C" data-lang="C"><span style="display:flex;"><span><span style="color:#75715e">// a.h
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">typedef</span> <span style="color:#66d9ef">enum</span> {
</span></span><span style="display:flex;"><span>    SYS_OK,
</span></span><span style="display:flex;"><span>    SYS_ERR_TIMEOUT,
</span></span><span style="display:flex;"><span>    SYS_ERR_BUSY,
</span></span><span style="display:flex;"><span>    SYS_ERR_INVALID_ARG,
</span></span><span style="display:flex;"><span>    SYS_ERR_NOT_FOUND
</span></span><span style="display:flex;"><span>} SysState;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// a.c
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>state_desc[] <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    [SYS_OK] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;System OK&#34;</span>,
</span></span><span style="display:flex;"><span>    [SYS_ERR_TIMEOUT] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Timeout&#34;</span>,
</span></span><span style="display:flex;"><span>    [SYS_ERR_BUSY] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;System Busy&#34;</span>,
</span></span><span style="display:flex;"><span>    [SYS_ERR_INVALID_ARG] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Invalid Argument&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// SYS_ERR_NOT_FOUND is missing here
</span></span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#a6e22e">main</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">&#34;State = %s</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, state_desc[SYS_ERR_NOT_FOUND]);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The issue is easy to spot: <code>SYS_ERR_NOT_FOUND</code> was added to the enum,
but the string table was not updated.</p>
<p>When the program evaluates <code>state_desc[SYS_ERR_NOT_FOUND]</code>, it reads past the
end of the array and eventually crashes.</p>
<p>Of 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.</p>
<p>The underlying issue is that we are maintaining <strong>two pieces of information that
must always stay consistent</strong>:</p>
<ul>
<li>the enum definition</li>
<li>the string table</li>
</ul>
<p>As long as these are maintained separately and rely on manual synchronization,
mistakes like this are inevitable.</p>
<p>What we really need is a way to eliminate this class of problems entirely.</p>
<h2 id="x-macros">X Macros</h2>
<p>While looking for a solution, I came across an article by Randy Meyers
published in <em>Dr. Dobb&rsquo;s Journal</em> titled <strong>The New C: X Macros</strong> <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.
The article introduces a technique that uses the C preprocessor to generate
code from a single data definition.</p>
<p>This technique is commonly known as <strong>X Macros</strong>.</p>
<p>The idea is simple: maintain a single data list, and generate the necessary
code structures by redefining a macro.</p>
<p>Let&rsquo;s modify the previous example to see how this works.</p>
<p>First, define a <strong>Single source of truth</strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-C" data-lang="C"><span style="display:flex;"><span><span style="color:#75715e">#define SYS_STATE_LIST                         \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    X(SYS_OK,              &#34;System OK&#34;)        \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    X(SYS_ERR_TIMEOUT,     &#34;Timeout&#34;)          \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    X(SYS_ERR_BUSY,        &#34;System Busy&#34;)      \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    X(SYS_ERR_INVALID_ARG, &#34;Invalid Argument&#34;) \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    X(SYS_ERR_NOT_FOUND,   &#34;Not Found&#34;)
</span></span></span></code></pre></div><p>This list becomes the master definition of our data.
Each entry is wrapped inside a placeholder macro <code>X()</code>.</p>
<p>The name <code>X</code> is simply a convention. It has no special meaning and can be
replaced with any name.</p>
<p>Next, we define the macro <code>X</code> to generate the enum:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-C" data-lang="C"><span style="display:flex;"><span><span style="color:#75715e">#define X(name, desc) name,
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">typedef</span> <span style="color:#66d9ef">enum</span> {
</span></span><span style="display:flex;"><span>    SYS_STATE_LIST
</span></span><span style="display:flex;"><span>} SysState;
</span></span><span style="display:flex;"><span><span style="color:#75715e">#undef X
</span></span></span></code></pre></div><p>Then we redefine <code>X</code> so that the same list generates the string table:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-C" data-lang="C"><span style="display:flex;"><span><span style="color:#75715e">#define X(name, desc) [name] = desc,
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>state_desc[] <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    SYS_STATE_LIST
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span><span style="color:#75715e">#undef X
</span></span></span></code></pre></div><p>If you come from dynamic languages such as Python or Java, this might look
somewhat like a lightweight form of reflection.</p>
<p>X Macros gather scattered information into a single data list. By redefining
and undefining <code>X</code> (<code>#undef</code>), the same data can be injected into multiple
code templates. Adding, removing, or reordering entries will not introduce
inconsistencies.</p>
<p>This technique works well in many situations where related data must stay
synchronized, for example:</p>
<ul>
<li>Managing error codes, states, or event types together with their descriptions</li>
<li>Generating command tables or protocol definitions</li>
<li>Serialization and deserialization</li>
<li>Configuration data initialization and access code generating</li>
</ul>
<h2 id="advanced-notes">Advanced Notes</h2>
<p>X Macros are powerful, but they do come with trade-offs. Macro-heavy code can
reduce readability and make debugging more difficult.</p>
<p>Some practical tips:</p>
<ul>
<li>
<p><strong>Improve readability</strong>: Andrew Lucas suggests passing the macro <code>X</code> as a
parameter to the data list to make the structure clearer <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
</li>
<li>
<p><strong>Large data sets</strong>: If the list becomes very long, you may hit compiler
line-length limits. Randy Meyers recommends placing the list in a separate<code>.def</code> or <code>.h</code> file and using <code>#include</code> to reuse it.</p>
</li>
<li>
<p><strong>Inspect preprocessed output</strong>: You can use <code>gcc -E</code> to view the expanded
source code. Many modern IDEs with language servers can also show this.</p>
</li>
<li>
<p><strong>Team communication</strong>: Not everyone is familiar with this technique. Good
comments and documentation help avoid confusion.</p>
</li>
<li>
<p><strong>Use it sparingly</strong>: Like most macro tricks, X Macros should be used
thoughtfully rather than everywhere.</p>
</li>
</ul>
<h2 id="summary">Summary</h2>
<p>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.</p>
<p>By maintaining a <strong>Single Source of Truth</strong> and generating code through macro
expansion, X Macros eliminate the risk of inconsistent duplicated definitions.</p>
<p>The 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&rsquo;s
toolbox.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>AI translated.  I discovered this link when I tried to find the source of this quote:<a href="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">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</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Randy Meyers. &ldquo;The New C: X macros&rdquo;, Dr.Dobb&rsquo;s 2001, accessible at:<a href="https://jacobfilipp.com/DrDobbs/articles/CUJ/2001/0105/meyers/meyers.htm">https://jacobfilipp.com/DrDobbs/articles/CUJ/2001/0105/meyers/meyers.htm</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Andrew Lucas. <a href="https://www.embedded.com/reduce-c-language-coding-errors-with-x-macros-part-1/">&ldquo;Reduce C-language coding errors with X macros&rdquo;</a>, Embedded.com, 2013.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item></channel></rss>