Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Share sizeof(array) between two modules

I want to share the value of sizeof(array) between two .c modules. The array is initialized in file A, so compiler knows the size at compile time and then I want to use the size of this array in another B file.

Example:
In A.c file:

int arr[] = {1, 2, 3};
.
.
.

for (int i = 0; i < sizeof(arr); i++); // that works

In A.h file:

extern int arr[];

In B.c file:

#include "A.h"
.
.
.

for (int i = 0; i < sizeof(arr); i++); // here compiler doesn't know size of this arr

Is there a way to make this work? I know why this doesn't work but maybe there is a sneaky trick to workaround this.

like image 835
dunajski Avatar asked Jun 26 '20 12:06

dunajski


3 Answers

Is there a way to make this work? I know why this doesn't work but maybe there is a sneaky trick to workaround this.

This unfortunately is not very sneaky, but it works...

In some.h

//declare as extern for project global scope
extern int arr[];
extern size_t gSizeArray;

Then in some.c

//define and initialize extern variables in 1 (and only one) .c file, 
int arr[] = { 1,2,3 };
size_t gSizeArray = sizeof(arr)/sizeof(arr[0]);

In someother.c that includes some.h

#include "some.h"
//you can now see the value of gSizeArray in this file

printf("%zu\n%d,%d,%d\n", gSizeArray, arr[0], arr[1], arr[2]);//should output

3
1,2,3

caveat
The value of using an extern in this fashion is that the value of that variable can change in one module, and that same value can be seen in any .c file that includes some.h

corollary
The problem of using an extern in this fashion is that the value of that variable can change in one module, and that same value can be seen in any .c file that includes some.h.

(or in other words, be careful. Globals, in particular extern globals can be helpful, but they can also be dangerous. Particularly for maintainers of the code who are not also the author of the code, who may not be aware a variable is of extern scope, and use it unwittingly in inappropriate ways.

By the way, there is probably more than you'll ever want to know about using extern scope in this post.

like image 81
ryyker Avatar answered Oct 12 '22 10:10

ryyker


Make the initializer a macro, share it through the header, and then you can use the compiler to recount the elements for the extern declaration:

//header.h
#define ARR_INIT { 1, 2, 3}
extern int arr[sizeof((int[])ARR_INIT)/sizeof(int)];

//file.c
#include "header.h"
int arr[] = ARR_INIT;

( On gcc/clang/tinycc, you can also do:

//header.h
#define ARR_INIT (int[]){ 1, 2, 3}
extern int arr[sizeof(ARR_INIT)/sizeof(ARR_INIT[0])];

//file.c
#include "header.h"
int arr[] = ARR_INIT;

which is more typesafe but won't work with -Wpedantic as standard C doesn't allow compound literals as initializers for objects with static storage duration. )

You could also share the size through a regular global, but that has disadvantages as such a size would no longer be an integer constant expression and so it wouldn't be usable where those are required (array sizes, bitfield-widths, case labels, static initializers).

like image 30
PSkocik Avatar answered Oct 12 '22 08:10

PSkocik


You can do it f.e. by declaring both, the size object (which contains the amount of elements of arr) and the array arr, with the extern storage-class specifier so that they have external linkage in the header A.h. This header you include in both .c source files.

The value of the size object as well as the size of the array arr (by its initializer list) is specified in A.c but can be used in B.c.


The A.h file:

 #include <stdio.h>     // for size_t.

 extern int arr[];
 extern size_t size;

The A.c file:

 #include "A.h"
 #include <stdio.h>     // for size_t. 

 int arr[] = { 1, 2, 3 };
 size_t size = sizeof (arr) / sizeof (arr[0]);

 for ( size_t i = 0; i < size; i++ ) 
 {
      arr[i] = arr[i] - 1;
 }

The B.c file:

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

 for ( size_t i = 0; i < size; i++ ) 
 {
      printf("%d\n", arr[i]);
 }

Output:

 0
 1 
 2

Side Note:

  • sizeof(arr) does not yield the amount of elements in arr; It yields the amount of bytes allocated for the whole array arr. Since arr is an array of type int and not f.e. char, where the amounts of elements is equal to the amount of allocated byte, this result is different to the amount of elements.

    To gain the amount of elements use sizeof(arr) / sizeof(arr[0]).

like image 1
RobertS supports Monica Cellio Avatar answered Oct 12 '22 09:10

RobertS supports Monica Cellio