5

I'm not really into C design patterns, so my doubt is potentially simple (although a little specific). The real application of this question is harder to explain, so let me simplify it.

Suppose I have an array, in which I want to store prime numbers. The number of primes this array contains is defined by NUMBER_OF_PRIMES, a constant defined at compile time.

Thus, we have:

unsigned primes[NUMBER_OF_PRIMES];

If the size was fixed, I could pre-compute the primes and initialize the array as usual:

unsigned primes[NUMBER_OF_PRIMES] = { 2, 3, 5, 7, ... };

But that would be rather ugly if NUMBER_OF_PRIMES were, let's say, greater than 200. I want some way to run a function at runtime, but before main(), that will put those primes numbers there. Of course I could do:

unsigned* primes = make_primes(NUMBER_OF_PRIMES);

which would allocate the necessary memory and run before main. The main problem is: this array would be in a header file, but it's value would contain something that's hidden inside the corresponding .c file. what I thought I could do is:

/* Header file */
unsigned primes[NUMBER_OF_PRIMES];

/* C file */
int nothing = initialize_primes(); /* This function would write the 
values to the array, using things that are not available in the
header (it is in the .c, so it can reference them), and return anything */

Another way is obviously putting initialize_primes() in the header file, and asking the user to call it inside the main function (like some libraries' init() function). However, I'd like not to force main() to contain a call to this function.

My question is if there is any elegant way to do this that is universally accepted/used, or if this is ridiculous and I should ask main() to call an init() function to avoid unnecessary, obscure code.

As I said, I'm not working with anything related to primes; this is just an example with the same challenge.

Best regards.

Gabriel
  • 1,803
  • 1
  • 13
  • 18
  • possible duplicate of [Calling some functions before main in C](http://stackoverflow.com/questions/4880966/calling-some-functions-before-main-in-c) – outis Oct 23 '11 at 22:49
  • @EvilTeach Why would you want to know which platform? – Khaled Alshaya Oct 23 '11 at 22:49
  • 3
    I think it's perfectly reasonable to require calling an initialization function to use your library. AFAIK, there aren't any features to allow you to do this any simpler in a portable way. – Jeff Mercado Oct 23 '11 at 22:50
  • @arak some platforms have specific methods for things like that. – EvilTeach Oct 24 '11 at 05:14

4 Answers4

7

Using an init function is the proper way to go. Don't forget to add a fini function, too, so people can release the memory if they want to (without knowing what your library does it might or might not be important but generally it's good to be able to free all memory - for example, when a library is used by a loadable module it usually doesn't want to leak memory when it's unloaded).

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
5

Why do you need it to run before main? The only reason I can think of is if you don't control main (ie, you're just a library that someone will call).

In that case, it's perfectly okay to insist that the caller call your initialisation function. The APIs form a contract between their code and yours and, if they break that contract, it's not your responsibility.

If you do control main then just call your own initialisation function right at the start. It doesn't need to happen any earlier.

If you decide to go down the static array route and you don't want to type in all the primes (as you state, they're not primes but I'm assuming they're computable), then you could write a separate program as part of your build tools (not deployed with your program).

It could pre-calculate the values based upon that constant and create a C file with the array that you could then compile and link to. That would at least remove the drudgery of typing them in.

That also moves the cost of calculation away from the user, resulting in faster startup (assuming the cost is non-trivial).

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
5

One trick that you can do is this:

// primes.c
static unsigned *p = NULL;

const unsigned *primes(void)
{
    if(p == NULL)
      {
        p = malloc((PRIMES_COUNT + 1) * sizeof *p);
        *p++ = 0; // if user accidentally frees p now, it will segfault
        // populate p
        atexit(primes_cleanup);
      }
    return p;
}

void primes_cleanup(void)
{
    if(p)
      {
        free(p - 1); // correct way to free the pointer
        p = NULL;    // now calling _cleanup twice is fine
      }
}

The user uses primes()[N] to get the desired element, and it's guaranteed to be initialized. Even if you store the pointer and use it later, it's guaranteed to work (unless someone cast away the const and changed your list when you weren't looking). If you still want variable-like syntax, use this:

// primes.h
const unsigned *primes(void);
void primes_cleanup(void);
#define PRIMES (primes())

To the end-user, PRIMES will look like any other variable. Win.

Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
1

There may be some nasty ways to do this, however i would suggest A) provide an init function to be called as required or B) if its a static array size, you could write a program offline to generate the array that is included. That way you can regenerate it later on if you need to change it. But A) is the more accepted way to do this

Adrian Brown
  • 456
  • 3
  • 14