Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing static variable with nonconstant value

Tags:

c

macros

From 21st century C book:

Static variables, even those inside of a function, are initialized when the program starts, before main, so you can’t initialize them with a nonconstant value.

//this fails: can't call gsl_vector_alloc() before main() starts
static gsl_vector *scratch = gsl_vector_alloc(20);

This is an annoyance, but easily solved with a macro to start at zero and allocate on first use:

#define Staticdef(type, var, initialization) \ 
static type var = 0; \
if (!(var)) var = (initialization);

//usage:
Staticdef(gsl_vector*, scratch, gsl_vector_alloc(20));

I don't understand what difference the macro made. Doesn't it do exactly the same thing after preprocessing?


like image 714
qed Avatar asked Nov 03 '14 15:11

qed


2 Answers

Doesn't it do exactly the same thing after preprocessing?

No, both not necessarily behave the same.

This initalisation is guaranteed to run only once:

static int i = 42; /* Initialisation */

This assignment

static int i = 0;
if (!i) /* line X */
  i = 42; /* Assignment */

is not, as everytime the program flow reaches line X and i equals 0 then i is set to 42 (again).

Examples:

#include <stdio.h>

void foo(int inew)
{
  static int i = 42;

  printf("%d\n", i);

  i = inew;
}

void bar(int inew)
{
  static int i = 0;
  if (!i)
    i = 42;

  printf("%d\n", i);

  i = inew;
}

int main(void)
{
  foo(43);
  foo(0);
  foo(44);

  printf("\n");

  bar(43);
  bar(0);
  bar(44);

  return 0;
}

Run it and see the difference:

42
43
0

42
43
42
like image 60
alk Avatar answered Oct 18 '22 04:10

alk


Preprocessor only replaces the text, so that the end result of Staticdef macro is:

static gsl_vector *scratch = 0 ;
if (!(scratch )) scratch = (gsl_vector_alloc(20));

You can type that yourself if you wish or use the macro.

This is of course different than the incorrect version:

static gsl_vector *scratch = gsl_vector_alloc(20);

I recommend not using the macro as it cannot be wrapped in a do{}while, and only obfuscates the code.

like image 23
2501 Avatar answered Oct 18 '22 05:10

2501