Home > Back-end >  C static array initialization with indexes
C static array initialization with indexes

Time:12-04

I have a static array in a class and an enum for the index of such array.

enum  MyEnum
{
   FIRST = 0,
   SECOND,
   LAST
}

class MyClass
{
public:
    static string names[LAST];
    
}

I'd like to initialize my static array to associate a value of the array to each enum type like this:

names[FIRST] = "First";
names[SECOND] = "Second";

I know that I can initialize the array upon declaration like this static string names[] = {"First", "Second"}, but I want to explicitly assign the value to the corresponding enum to avoid errors.

In Java, there's a static block where you can do this kind of initialization, but I don't think that this is the case in C . Is there an elegant way of doing this? I can't use std on my project, so the solution has to avoid any library usage.

Thanks in advance.

CodePudding user response:

Write a function to initialize it. Function can't return an array - if you want to use an array, return a whole object that has an array inside it. Or you can return something dynamically allocated, a map or a vector.

#include <array>
#include <string>

enum  MyEnum {
    FIRST = 0,
    SECOND,
    LAST
};

std::array<std::string, LAST> construct_names() {
    std::array<std::string, LAST> r;
    r[FIRST] = "first";
    r[SECOND] = "second";
    return r;
}

static auto names = construct_names();

I can't use std on my project, so the solution has to avoid any library usage.

Roll your own types.

enum  MyEnum {
    FIRST = 0,
    SECOND,
    LAST
};

template<typename T, unsigned N>
struct MyArray {
    T data[N];
    T &operator[](unsigned i) {
        return data[i];
    }
};

MyArray<const char *, LAST> construct_names() {
    MyArray<const char *, LAST> r;
    r[FIRST] = "first";
    r[SECOND] = "second";
    return r;
}

static auto names = construct_names();

You may also want to read How to initialize private static members in C ? or similar, as for class initialization you need to do like, there will be some type repetition:

class MyClass {
public:
    static MyArray<const char *, LAST> names;
};

MyArray<const char *, LAST> MyClass::names = construct_names();

CodePudding user response:

Yes you can do it in simple way using __attribute__((init_priority(101))) and __attribute__((constructor(102)))

#include <string>
#include <iostream>

using namespace std;

enum  MyEnum
{
   FIRST = 0,
   SECOND,
   LAST
};


class MyClass
{
public:
    static string names[LAST];
    
};

__attribute__((init_priority(101))) string MyClass::names[LAST];

__attribute__((constructor(102))) void foo()
{
    MyClass::names[FIRST] = "First";
    MyClass::names[SECOND] = "Second";
}


int main()
{
    MyClass m;
    for (int i = 0; i < LAST; i  ) {
        cout << m.names[i] << "\n";
    }
}

Output:

First
Second

Explanation in simple:

Before even code loads, first it initialize string MyClass::names[LAST]; because we added __attribute__((init_priority(101))) then it calls foo() automatically, The function name can be any it does not matter, it can be init as well no need to be foo. The order of initialization is based on number 101 and 102. If we change the order then it wont work.

For more info refer: https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html#index-init_005fpriority-variable-attribute

Declaimer: This initialization is not bound to the class, if you keep on adding like this for all the classes then you are in big trouble and you need to keep on maintain a list of orders. This inits are for the entire binary or library

  •  Tags:  
  • c
  • Related