1

There is a similar discussion on Count number of elements for static array initialization in C - but I still cannot tell if all the opportunities in my case are exhausted or not.

Consider the following example files (I ran these in https://www.onlinegdb.com/online_c_compiler which can handle multiple files)

ext.h

#include <inttypes.h>

#define _my_data  0x11, 0x22, 0x33, 0x44, 0x55, 0x66
extern const uint8_t mydata_arr[];

ext.c

#include "ext.h"

const uint8_t mydata_arr[] = { _my_data };

main.c

#include <stdio.h>
#include "ext.h"

int main()
{
    printf("First mydata_arr item: 0x%02X\n", mydata_arr[0]); // ok
    printf("  size: %d\n", sizeof(mydata_arr));
    return 0;
}

This fails with:

main.c:15:34: error: invalid application of ‘sizeof’ to incomplete type ‘const uint8_t[]’ {aka ‘const unsigned char[]’}
   15 |     printf("  size: %d\n", sizeof(mydata_arr));
      |                                  ^

The comment(s) I found in https://www.reddit.com/r/C_Programming/comments/esu4ff/error_invalid_application_of_sizeof_to_incomplete/ffc6u19/ I think sums up the problem:

The compiler can’t practically see arbitrary definitions outside of the starting file or what it #includes, because definitions might not exist yet (or at all, up until load time, or at all, ever).

the compiler compiles each source file individually, with references to elements in external source files that need to be handled by the linker. This is why we generally either pass an array with a length in the function prototype ...

If the compiler can’t directly see the size of the thing, it can’t give you a value for sizeof.

OK, so I understand why I cannot get sizeof(mydata_arr) for a extern const uint8_t mydata_arr[] from a header file.

The thing is, though - my data is actually in a #define _my_data (which is however not a string, due to lack of quotation marks - though I'm not really sure how the preprocessor otherwise sees the contents of _my_data).

So, I was wondering: is there a way in C to use the "define" _my_data, to obtain the size of the corresponding array -- without necessarily having to use sizeof, which would require to explicitly say extern const uint8_t mydata_arr[6]; in the header file?

EDIT:

  • Question was wrongly worded (thankfully the accepted answer answered what I wanted to ask, instead of what I wrote :)). It should have been: is there a way in C to use the "define" _my_data, to obtain the size of the corresponding array - in such a way, that I do not have to specify the size explicitly via extern const uint8_t mydata_arr[6] in the header file - but I can still use sizeof in code, to get the correct size (number of elements) in the array?
  • I need to have the declaration as extern in a header file, because in my actual use case, other files than ext.c and main.c would want to use mydata_arr - and all of these would in principle want to also know the sizeof mydata_arr;
  • I'd rather not hold the count/number of elements of mydata_arr in a separate variable - considering that sizeof already exists
sdbbs
  • 4,270
  • 5
  • 32
  • 87
  • Define `mydata_arr` in `main.c` (and not in `ext.c`). – Jean-Baptiste Yunès May 24 '22 at 14:29
  • Whomever defines the array [in a `.c` file] does: `const uint8_t mydata_arr[] = { _my_data }; const size_t mydata_count = sizeof(mydata_arr);` Then, in the `.h` file, you have: `extern const uint8_t mydata_arr[]; extern const size_t mydata_count;` – Craig Estey May 24 '22 at 14:46

1 Answers1

4

You could use a compound literal as an operand of sizeof when declaring mydata_arr.


#define _my_data  0x11, 0x22, 0x33, 0x44, 0x55, 0x66
extern const uint8_t mydata_arr[sizeof ((uint8_t[]) {_my_data}) / sizeof(uint8_t)];
                                        ^^ compound literal ^^

BTW. The sizeof(uint8_t) is guaranteed to be 1 as it is the same size of unsigned char (though technically they don't have to be same type).

tstanisl
  • 13,520
  • 2
  • 25
  • 40
  • 2
    A supporting helper macro: `#define ARGSCOUNT(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))` which would allow for `extern const uint8_t mydata_arr[ARGSCOUNT(_my_data)];` – Ted Lyngmo May 24 '22 at 14:33
  • Well, there's one issue with `uint8_t`: It doesn't need to exist at all, in contrast to `unsigned char` – if the latter is larger than 8 bits (some DSP out there have that still today...). Admitted, declaring the array at all wouldn't be possible either then ;) – Aconcagua May 24 '22 at 14:37