mikroblogi/posts/2024-10-11-self-referential-initialization-c.html
Juhani Krekelä e088ff89b7 Haunt
2026-03-16 19:45:29 +02:00

46 lines
2 KiB
HTML

title: Self-referential variable initialization in C
date: 2024-10-11 00:00
originally-zola: self-referential-initialization-c
---
<p>I was reading the <a href="https://github.com/libsdl-org/SDL_shader_tools/blob/main/docs/README-shader-language-quickstart.md">SDL Shader Language
Quickstart</a>,
which (at the moment) mostly consists of explanations about how the
language differs from C.</p>
<p>One difference listed caught my eye: variable initialization can't
reference itself.
To quote,</p>
<blockquote>
<p>Why does C even allow this?</p>
<pre><code>int x = x + 1;
</code></pre>
<p>In C, x is in scope as soon as the parser sees int x, but this allows you to reference a variable that is definitely not initialized during its own initializer! Doing so is always a bug, so we just don't allow it.</p>
</blockquote>
<p>I would consider myself fairly knowledgeable about the weird corners of C,
but I had never come across this "feature"!</p>
<p>As stated, using the uninitialized value of the variable is going to
be undefined behaviour in C.
However, I did not immediately see why taking a pointer to the variable
would be.
So, as long as we only use the pointer of the value in its definition, that
ought to be fine?</p>
<p>Normally, doing</p>
<pre><code>type x = &amp;x;
</code></pre>
<p>is going to fail because the types <code>type</code> and <code>type*</code> are not compatible.
However, in C (but not C++!) you can implicitly cast between <code>void*</code> and
any other pointer type, including <code>void**</code>.
This means we should be able to do</p>
<pre><code>void *x = &amp;x;
</code></pre>
<p>To test this, I made the following test program</p>
<pre><code>#include &lt;stdio.h&gt;
int main(void) {
void *x = &amp;x;
&#x2F;&#x2F; We need an explicit cast for &amp;x here, since printf is a
&#x2F;&#x2F; varargs function.
printf(&quot;x = %p, &amp;x = %p\n&quot;, x, (void*)&amp;x);
}
</code></pre>
<p>And with GCC 14.2.0, this does indeed work, with zero warnings with the
flags <code>-std=c23 -Wall -Wextra -pedantic</code>!</p>