0

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.

4
  • 1
    It shouldn't be an intptr_t, it should be a proper function pointer. Why ignore it since that's probably the core of your issue? Commented Aug 20, 2013 at 22:05
  • @Mat: That field in the struct is also used to store integers in parts of the code. I am working with legacy code and this struct is used in well over 5k files - sometimes the field stores an int, and other times, it holds a raw ptr. The best I can do is to change it to an intptr_t, this will require the least modification to the body of existing code. Commented Aug 20, 2013 at 22:17
  • 1
    An intptr_t is not guaranteed to be able to hold a function pointer value without loss of information, though it's likely to be able to. (Probably uintptr_t would make slightly more sense than intptr_t.) Commented Aug 20, 2013 at 22:49
  • 1
    @KeithThompson to add to this, if the implementation is POSIX it is guaranteed. Commented Aug 20, 2013 at 23:02

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

+1 for honing in straight on the problem, and for the detailed explanation.
1
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.

7 Comments

My bad, I will correct the code I submitted. This is not the cause of the problem I am having though
@HomunculusReticulli did you see the last edit? I think this is the cause of your error message.
@HomunculusReticulli ok, another edit on your original question. Are you sure macro MAX_FUNC_NAME_LEN is defined in your program, try to use some fixed value like 256 to test. Also please use some valid examples in your questions.
Yes, the constant is defined. Apologies for the previous mistakes in the sample code.
@HomunculusReticulli OK so assuming the constant is an int greater or equal to 5, your code snippet is valid and no conforming compiler could refuse it. Your actual program is probably slightly different. Your should create a single standalone test case which shows the failure.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.