As a secondary answer to provide a method to do what the OP wanted but assuming he needed data hiding, I present this code that builds on my first answer and provides generic access to an element type in one C file and providing only an opaque data type in the header file. Please note that to get a point across about what are pointers I use element * however they could have all been replaced by ELEM_HANDLE that I define as a type in the header. ELEM_HANDLE abstracts away the fact that we are dealing with element pointers. Since we use an opaque type we make available methods that can be called (defined in element.h) to work on our opaque type.
element.h:
#include <stdint.h>
typedef struct element element;
typedef element *ELEM_HANDLE;
extern element *element_new();
extern void element_delete(element *elem);
extern void element_set_value_raw(element *elem, uint16_t value_raw);
extern uint16_t element_get_value_raw(element *elem);
extern void element_set_value_scaled(element *elem, float value_scaled);
extern float element_get_value_scaled(element *elem);
extern void element_set_desc(element *elem, char *desc);
extern char *element_get_desc(element *elem);
element.c:
#include <stdint.h>
#include <stdlib.h>
typedef struct element
{
uint16_t value_raw;
float value_scaled;
char *desc;
} element;
element *element_new()
{
return calloc(1, sizeof(element));
}
void element_delete(element *elem)
{
free(elem);
}
void element_set_value_raw(element *elem, uint16_t value_raw)
{
elem->value_raw = value_raw;
}
uint16_t element_get_value_raw(element *elem)
{
return elem->value_raw;
}
void element_set_value_scaled(element *elem, float value_scaled)
{
elem->value_scaled = value_scaled;
}
float element_get_value_scaled(element *elem)
{
return elem->value_scaled;
}
void element_set_desc(element *elem, char *desc)
{
elem->desc = desc;
}
char *element_get_desc(element *elem)
{
return elem->desc;
}
testelem.c:
#include <stdio.h>
#include "element.h"
#define REG_READ_COUNT 2
void dostuff(element *sv[], int arrLen)
{
int index;
element *curelem;
uint16_t raw;
float scaled;
char *desc;
for (index = 0; index < arrLen ; index++){
curelem = sv[index];
raw = element_get_value_raw(curelem);
scaled = element_get_value_scaled(curelem);
desc = element_get_desc(curelem);
/* Do more interesting stuff here */
printf("%s, %d, %.4f\n", desc, raw, scaled);
}
}
int main()
{
unsigned int index;
element *sv[REG_READ_COUNT]; /* array of element pointers*/
char desc1[] = "The answer to everything";
char desc2[] = "OtherStuff";
/* Initialize an array of pointers to element items */
for (index = 0; index < sizeof(sv) / sizeof(element *); index++)
sv[index] = element_new();
element_set_value_raw(sv[0], 42);
element_set_value_scaled(sv[0], 6.66f);
element_set_desc(sv[0], desc1);
element_set_value_raw(sv[1], 123);
element_set_value_scaled(sv[1], 456.7f);
element_set_desc(sv[1], desc2);
dostuff(sv, REG_READ_COUNT);
/* free the array of pointers to element items*/
for (index = 0; index < sizeof(sv) / sizeof(element *); index++)
element_delete(sv[index]);
return 0;
}
Note that I took liberties to pass in the array length to dostuff beside the array of element pointers. This provides dostuff with enough information to determine how many elements are in the array. This should compile (and run) properly on C89 or above and C++ compilers (provided you rename the .c files to .cpp).
I present this answer because using forward declarations and opaque types is how many "C" language shared objects are created. This mechanism allows the element source to be compiled into an independent library or shared object and used without knowing what the element data type looks like. In essence we provide an interface contract between the modules that use us and the library. If we modify the internals of the structure element in element.cpp our modules that use it will not need to be recompiled (just re-linked). client code that uses the library would need to be rebuilt if we modify the interface(contract).
So in the end forward references (opaque types) can be used to hide C data type internals and provide a layer of abstraction. This type of mechanism is often used by shared objects (.so files) to build complex libraries that can be used by C programs.
X *xand rejectsX x[]elementthen there is no answer given here that would be acceptable. If no data hiding was needed than the OPs choice of answer makes sense. So the simple question to remove all ambiguity is - Is data hidingelementrequired?