15

Defines the type x and an array X of that type.

x.h:

typedef struct _x {int p, q, r;} x;
extern x X[];

Separate file to keep the huge honking array X.

x.c:

#include "x.h"
x X[] = {/* lotsa stuff */};

Now I want to use X:

main.c:

#include "x.h"

int main()
{
    int i;

    for (i = 0; i < sizeof(X)/sizeof(x); i++) /* error here */
        invert(X[i]);

    return 0;
}

main.c won't compile; the error is:

error: invalid application of ‘sizeof’ to incomplete type ‘struct x[]’

How do I get the size of X without hardcoding it?

2
  • if x is a struct you usually have to specify sizeof(struct x) Commented Apr 22, 2014 at 21:05
  • 1
    no need to use struct if you typedef Commented Apr 22, 2014 at 21:06

5 Answers 5

18

In x.h add:

extern size_t x_count;

In x.c add:

size_t x_count = sizeof(X)/sizeof(x);

Then use the variable x_count in your loop.

The division has to be done in the compilation unit that contains the array initializer, so it knows the size of the whole array.

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

8 Comments

This may solve OP's specific problem, but in general it's deficient since count is still not a constant expression and cannot be used in all places you would use sizeof. Also, int is the wrong type. It should be size_t.
It's as close as you can get with separately compiled modules. The size can only be a constant expression if the array initialization is in the same compilation unit.
The result of sizeof is a constant expression, for the purposes of initializing a global variable. You're completely right about using size_t however.
Thank you, I used this solution with a wrapper #define XCOUNT x_count for legacy purposes.
I don't see a problem with declaring x_count as const size_t
|
3

If it is possible to place a termination indicator at the end of the array, such as:

x X[] = {/* lotsa stuff */, NULL};

It might be that the number of elements in the array would be irrelevant:

#include "x.h"

int main()
   {
   x *ptr = X;

   while(ptr)
      invert(ptr++);

   return 0;
   }

If the number of elements in the array is needed, the above method can be also be used to count the elements.

Comments

3

Here a solution using compound literals:

in .h

typedef struct _x {int p, q, r} x;

#define LOTSA_STUFF        {1, 2, 3}, {4, 5, 7}
#define LOTSA_STUFF_SIZE  sizeof ((x[]) {LOTSA_STUFF})

extern x X[LOTSA_STUFF_SIZE];

and in .c

x X[LOTSA_STUFF_SIZE] = {LOTSA_STUFF};

For the definition in .c, you can even do better and use a static assert (definition of the STATIC_ASSERT is let as an exercise for the reader ;):

x X[] = {LOTSA_STUFF};

STATIC_ASSERT(sizeof X != LOTSA_STUFF_SIZE, "oops, sizes are not equal");

3 Comments

What a cool example. I've never used compound literals and wasn't familiar with the syntax. There is a really good article on Dr. Dobb's for people interested in learning more.
Oh... and you are missing an 'F' on your LOTSA_STUF in the fourth line of the .h example.
This version still does require having the initial data visible in the header, which I think OP was trying to avoid.
0

If you simply include x.h, the compiler has no idea what the real size of X is. Just by looking at x.h, there is no way to guess. You have to declare X with a size:

extern x X[15];

1 Comment

The whole point of using sizeof(X)/sizeof(x) is so you don't have to hard-code the number of elements, it's sized automatically from the number of elements in the array initializer.
0

You can't do that. But you can provide a way to get the size.

In addition to

extern x X[];

Add

extern size_t xArraySize;

or, preferably,

extern size_t xArraySize(void);

in x.h

Define it in x.c.

Change your loop to:

for (i = 0; i < xArraySize(); i++)
    invert(X[i]);

2 Comments

Why is the function preferable?
@Rick it allows you to hide the details of how the data is stored.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.