EN VI

Arrays - Use of compound literal inside a function to init a variable in C?

2024-03-14 18:00:07
How to Arrays - Use of compound literal inside a function to init a variable in C

This question follows this one : Is there a syntax in C to DIRECTLY INIT a struct member that is a const array of constant literal?.

Eric Postpischil gave me a solution using compound literals.

Now, I would like to initialise my variables in a function. But, inside a function, compound literal has automatic storage duration and datas are needed outside this function. To solve this problem, I used the static keyword but I am not sure that is a good idea.

This is the initial code (with initialisation in the main)

#include <stdio.h>

typedef struct {
  const char* name;
  const int nb;
  const char* const* list;
} valid_options_t;

void print_options (const valid_options_t* option) {
  printf("Option Name : %s\n",option->name);
  for (int i=0; i < option->nb; i++) printf("\t%s\n",option->list[i]);
  printf("---------\n");
}
int main() {

  const valid_options_t my_size_opts = {.name="size", .nb=3, .list= (const char * const[]) {"large", "medium", "small"} };
  const valid_options_t my_color_opts = {.name="color", .nb=4, .list= (const char * const[]) {"orange", "yellow", "white", "red"} };
  const valid_options_t my_form_opts = {.name="shape", .nb=2, .list= (const char * const[]) {"circle", "square"} };

  print_options (&my_size_opts);
  print_options (&my_color_opts);
  print_options (&my_form_opts);

}

And the code with initialisation in a function.

#include <stdio.h>

typedef struct {
  const char* name;
  const int nb;
  const char* const* list;
} valid_options_t;

void print_options (const valid_options_t* option) {
  printf("Option Name : %s\n",option->name);
  for (int i=0; i < option->nb; i++) printf("\t%s\n",option->list[i]);
  printf("---------\n");
}

void init_coumpond_literal(valid_options_t *(*my_opts)[3]) {
  (*my_opts)[0] = &(static valid_options_t){.name="size", .nb=3, .list= (static const char * const[]) {"large", "medium", "small"} };
  (*my_opts)[1] = &(static valid_options_t){.name="color", .nb=4, .list= (static const char * const[]) {"orange", "yellow", "white", "red"} };
  (*my_opts)[2] = &(static valid_options_t){.name="shape", .nb=2, .list= (static const char * const[]) {"circle", "square"} };
}

int main() {

  const int feature_nb=3;
  
  valid_options_t *my_size_opts[feature_nb];
  
  init_coumpond_literal(&my_size_opts);
  
  for (int i=0; i < feature_nb; i++)
    print_options (my_size_opts[i]);
}

Is it the right way to do that ? And how can I free these variables ?

Solution:

The original code is fine for C23, which is yet to be published at the time of writing, but for portability to earlier C standards, the static qualifier needs to be removed from the compound literals, but then they would no longer have static storage duration as required, so another solution would be required. One possibility is to replace the compound literals with static variables of limited scope, for example:

void init_coumpond_literal(valid_options_t *(*my_opts)[3]) {
  static valid_options_t opts[3] = {
    {.name="size", .nb=3, .list= (const char * const[]) {"large", "medium", "small"} },
    {.name="color", .nb=4, .list= (const char * const[]) {"orange", "yellow", "white", "red"} },
    {.name="shape", .nb=2, .list= (const char * const[]) {"circle", "square"} }
  };
  (*my_opts)[0] = &opts[0];
  (*my_opts)[1] = &opts[1];
  (*my_opts)[2] = &opts[2];
}

The compound literals such as (const char * const[]) {"large", "medium", "small"} used within the initializers of opts will have static storage duration.

The opts array is modifiable outside the function because it is not const. If that is undesirable, declare opts as static const valid_options_t opts[3];, and make appropriate changes elsewhere in the code.

Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login