46 lines
2 KiB
HTML
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 = &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 = &x;
|
|
</code></pre>
|
|
<p>To test this, I made the following test program</p>
|
|
<pre><code>#include <stdio.h>
|
|
|
|
int main(void) {
|
|
void *x = &x;
|
|
// We need an explicit cast for &x here, since printf is a
|
|
// varargs function.
|
|
printf("x = %p, &x = %p\n", x, (void*)&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>
|