Created
July 2, 2023 19:46
-
-
Save fidergo-stephane-gourichon/792c194e1b051a70995c27b5af8df92d to your computer and use it in GitHub Desktop.
In C, compile time constant structs and array with deep self-reference.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Summary: In C, compile time constant structs and array with deep self-references. | |
** Context: const and compile-time constants | |
Constructs fully determined at compile time have some benefits. | |
But const in C is weaker than constexpr that C++ has. | |
As prog-fh summarizes on | |
https://stackoverflow.com/questions/66144082/why-does-gcc-clang-handle-code-slightly-differently-example-given | |
> "The const means « I swear that I won't change the value of this variable » (or the compiler will remind me!). But it does not | |
> mean that it could not change by another mean I don't see in this compilation unit; thus this is not exactly a constant." | |
One example of invalid C: | |
const int mysize = 2; | |
const int myarray[mysize]; | |
gcc: error: variably modified ‘myarray’ at file scope | |
clang: warning: variable length array folded to constant array as an extension [-Wgnu-folding-constant] | |
const int myarray[mysize]; | |
** Good news: C can do compile time constant structs and array with deep self-references. | |
Yes, in C you can define and fully declare complex data structures that are accepted as compile-time constants, *including | |
pointers to parts of itself*. | |
See "self-contained, statically allocated, totally const data structure with backward and forward references (pointers)?" for a | |
previous example at | |
https://stackoverflow.com/questions/47037701/can-c-syntax-define-a-self-contained-statically-allocated-totally-const-data-s | |
The code below compiles without warning. | |
gcc -S -W -Wall -Wextra self_referencing_construct_with_deep_self_references.c | |
*/ | |
#include <stdio.h> // for NULL | |
/* Example too trivial to be actually useful. */ | |
const int mysize = 2; | |
const int myarray[mysize]; | |
struct selfref | |
{ | |
const struct selfref *const pointer; | |
}; | |
const struct selfref permutation[2] = { {&permutation[1]}, {&permutation[0]} }; | |
void permutation_check(void) | |
{ | |
printf("Adresses:\n%p\n%p\n", &(permutation[0]), &(permutation[1])); | |
printf("Pointed addresses:\n%p\n%p\n", permutation[0].pointer, permutation[1].pointer); | |
} | |
/* Example hinting at the existence of real-life uses. */ | |
struct question_answers | |
{ | |
const char *const question; | |
const char *const answer1; | |
const struct question_answers *const next1; | |
const char *const answer2; | |
const struct question_answers *const next2; | |
}; | |
const struct question_answers dialog_as_array[] = { | |
{ "Which pill?", | |
"Red pill", &dialog_as_array[2], | |
"Blue pill", &dialog_as_array[1] }, | |
{ "You wake up in your bed. The story ends. ", | |
"Believe it was all a dream.", NULL, | |
"Realize matrix has won.", NULL }, | |
{ "Welcome to the Real World. What next?", | |
"Become Neo.", &dialog_as_array[4], | |
"Give up.", &dialog_as_array[3] }, | |
{ "Mister Anderson!", | |
"Billions of people living out their lives, oblivious.", NULL, | |
"Evolution, like the dinosaur.", NULL }, | |
{ "Where we go from there is a choice I leave to you.", | |
"Go crazy.", NULL, "This is fine.", NULL }, | |
}; | |
struct dialog | |
{ | |
const struct question_answers entry; | |
const struct question_answers blue_pill_taken; | |
const struct question_answers red_pill_taken; | |
const struct question_answers red_pill_taken_give_up; | |
const struct question_answers red_pill_taken_become_neo; | |
}; | |
const struct dialog dialog_as_struct = { | |
.entry = { "Which pill?", | |
"Red pill", &dialog_as_struct.red_pill_taken, | |
"Blue pill", &dialog_as_struct.blue_pill_taken }, | |
.blue_pill_taken = { "You wake up in your bed. The story ends. ", | |
"Believe it was all a dream.", NULL, | |
"Matrix has won.", NULL }, | |
.red_pill_taken = { "Welcome Neo to the Real World. What next?", | |
"Become Neo.", &dialog_as_struct.red_pill_taken_become_neo, | |
"Give up.", &dialog_as_struct.red_pill_taken_give_up }, | |
.red_pill_taken_give_up = { "Mister Anderson!", | |
"Billions of people living out their lives, oblivious.", NULL, | |
"Evolution, like the dinosaur.", NULL }, | |
.red_pill_taken_become_neo = { "Where we go from there is a choice I leave to you.", | |
"Go crazy.", NULL, "This is fine.", NULL }, | |
}; | |
int main(void) | |
{ | |
permutation_check(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment