Homunculus Reticulli
Homunculus Reticulli

Reputation: 68426

Initializing an array of structs (compiler error: initializer element is not constant)

I am trying to initialize a C struct using the following code:

/* header file */

typedef struct _funky {
   int  func_id;  /* I know this should be intptr_t, but ignore for now ... */
   char func_name[MAX_FUNC_NAME_LEN];
} Funky;


double func1(double d1, double d2, double d3);
double func2(double d1, double d2, double d3);
double func3(double d1, double d2, double d3);
double func4(double d1, double d2, double d3);


/* .c file */
Funky fk[4] = {
                 {(int)func1, "func1"}, /* <- gcc barfs here ... */
                 {(int)func2, "func2"},
                 {(int)func3, "func3"},
                 {(int)func4, "func4"}
              };

When I attempt to compile this (gcc 4.6.3), I get the following errors:

error: initializer element is not constant
error: (near initializer for 'fk[0].func_id')

How I can fix this error?

[[Edit]]

After a brief chat with ouah, I have found the reason for this error - it is to do with the function definitions being used to initialize the array. Some of the definition are in different translation units, and others in different modules. All of which means (IIUC) that the functions will not be defined at compile time.

Short of writing an initialization function (which will require extensive mod in existing code) I'm not sure how to solve this - and I'm not sure how it compiled under previous versions of gcc either.

Upvotes: 0

Views: 2382

Answers (2)

Jonathan Leffler
Jonathan Leffler

Reputation: 753695

The function definitions are not material to the problem. The type used for func_id is, though.

Consider this code:

#include <stdint.h>
#define MAX_FUNC_NAME_LEN  6

typedef uintptr_t ptr_t;

typedef struct Funky
{
   ptr_t  func_id;  /* I know this should be intptr_t, but ignore for now ... */
   char func_name[MAX_FUNC_NAME_LEN];
} Funky;

double func1(double d1, double d2, double d3);
double func2(double d1, double d2, double d3);
double func3(double d1, double d2, double d3);
double func4(double d1, double d2, double d3);

Funky fk[4] = {
                 {(ptr_t)func1, "func1"}, /* <- gcc barfs here ... */
                 {(ptr_t)func2, "func2"},
                 {(ptr_t)func3, "func3"},
                 {(ptr_t)func4, "func4"}
              };

As written, using uintptr_t, this compiles cleanly under GCC 4.8.1 on Mac OS X 10.8.4 (64-bit compilation). Change the type of ptr_t to int and you get a pile of warnings. The trouble is that the 64-bit address constants don't fit into a 32-bit int, so the loader would have to generate code to truncate the addresses, which makes them insufficiently constant. With a 32-bit compilation, the code using int compiles cleanly too.

So, use a big enough type (uintptr_t recommended) and you will be OK. The "I know it should be intptr_t but ignore for now" comment is the source of your trouble; don't ignore it.

Upvotes: 1

ouah
ouah

Reputation: 145829

typedef _funky {
   int  func_id;  /* I know this should be intptr_t, but ignore for now ... */
   char func_name[MAX_FUNC_NAME_LEN];
} Funky;

there is a missing struct keyword here.

Also:

Funky fk[3] = {
                 {(int)func1, "func1"}, /* <- gcc barfs here ... */
                 {(int)func2, "func2"},
                 {(int)func3, "func3"},
                 {(int)func4, "func4"}
              };

You have 3 elements in your array but you initialize it with 4 initializers.

And as noted in the comments casting a function pointer to a int is probably a bad idea. There is absolutely no guarantee a function pointer value would fit in an int object.

Upvotes: 1

Related Questions