I am supposed to make a program based on a header file and some further description. The problem working with opaque type is needed. Opaque struct is declared in header file with some other functions. But each function is supposed to have its own .c file and here comes the question. What should I do or where should I define the opaque struct so my functions can work with that?
I have files like:
header.h source.c(main) function1.c fuction2.c etc.
And in this situation I have no idea what to do.
Your global header file should define a type name without its implementation, along with prototypes of functions to create, destroy and handle data of that type.
#ifndef HEADER_H_
#define HEADER_H_
struct XyzData;
typedef struct XyzData XYZDATA;
typedef struct XyzData *P_XYZDATA;
P_XYZDATA CreateEmptyXyzData();
P_XYZDATA CreateFilledXyzData(int param1, int param2);
void DestroyXyzData(P_XYZDATA pData);
int ModifyXyzData(P_XYZDATA pData, int action, int param);
#endif
Then you need an internal header, which provides an implementation for the structure.
#ifndef XYZINTHEADER_H_
#define XYZINTHEADER_H_
#include "header.h" // include the XyzData declaration
struct XyzData { // and add its definition
int par1;
int par2;
};
#endif
Then files with implementations for specific routines will use the internal header, because they need to know the structure details to access them.
#include "xyzintheader.h"
#include <stdlib.h>
P_XYZDATA CreateEmptyXyzData() {
return calloc(1, sizeof(XYZDATA));
};
#include "xyzintheader.h"
#include <stdlib.h>
P_XYZDATA CreateFilledXyzData(int param1, int param2) {
if (P_XYZDATA pData = malloc(sizeof(XYZDATA))) {
pData->par1 = param1;
pData->par2 = param2;
return pData;
}
return NULL;
};
#include "xyzintheader.h"
#include <stdlib.h>
void DestroyXyzData(P_XYZDATA pData) {
free(pData);
}
#include "xyzintheader.h"
int ModifyXyzData(P_XYZDATA pData, int action, int param) {
if (! pData)
return -1;
switch (action) {
case 0:
// do something
pData->par1 = pData->par2 = 0;
return 0;
case 1:
// do something
pData->par1 += param;
pData->par2 -= param;
return 0;
}
return -2;
}
And external modules will use the public header, because they only need to know the structure exists and what tools to use to handle it.
#include "header.h"
void SomeExternalLogic()
{
if (P_XYZDATA pData = CreateEmptyXyzData()) {
ModifyXyzData(pData, 0, 0);
ModifyXyzData(pData, 1, 3);
if (ModifyXyzData(pData, 13, 17) < 0)
WriteSomeErrorMessage();
DestroyXyzData(pData);
}
}