Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to declare an opaque structure pointer interface

Tags:

c

I'm trying to architect some C code such that the .c file and private .h file define a rather complex structure, but a public facing header file only requires pointers to that structure type. What I tried was this:

publicRadio.h

typedef struct _radio Radio;
void radioReceive(Radio *radio, ....);

privateRadio.h

#include <publicRadio.h>
struct _radio {
    ...
    ...
}

radio.c

#include <publicRadio.h>
#include <privateRadio.h>

void radioReceive(Radio *radio, ....)
{
    ...
}

When I try to compile this though, I get something like

radio.c:91:9: error: parameter 'radio' has just a forward declaration
radio.c:90:6: error: conflicting types for 'radioReceive'
publicRadio.h:29:6: note: previous declaration of 'radioReceive' was here

I'm trying to emulate the pattern I've seen in other libraries that have public facing APIs that expose their structures through functions, but hide the gory details. What is the recipe one uses to accomplish that?

like image 463
Travis Griggs Avatar asked Dec 18 '12 19:12

Travis Griggs


People also ask

What is an opaque pointer in C?

In computer programming, an opaque pointer is a special case of an opaque data type, a data type declared to be a pointer to a record or data structure of some unspecified type. Opaque pointers are present in several programming languages including Ada, C, C++, D and Modula-2.

What are opaque structures?

In computer science, an opaque data type is a data type whose concrete data structure is not defined in an interface. This enforces information hiding, since its values can only be manipulated by calling subroutines that have access to the missing information.

What is opaque pointer in Swift?

Opaque pointers are used to represent C pointers to types that cannot be represented in Swift, such as incomplete struct types.

What is an opaque object handle?

An opaque object and its handle are significant only at the process where the object was created, and cannot be transferred to another process. MPI provides certain predefined opaque objects and predefined, static handles to these objects. Such objects may not be destroyed.


2 Answers

This pattern is normally implemented like this:

radio.h

#ifndef RADIO_H
#define RADIO_H

typedef struct _radio Radio;
void radioReceive(Radio *radio, ....);

#endif

radio.c

#include "radio.h"

struct _radio {
    // _radio struct implementation
};

void radioReceive(Radio *radio, ....) {
    // radioReceive implementation
}

main.c

#include "radio.h"
.... // use Radio, radioReceive, etc.
like image 161
Matt Eckert Avatar answered Sep 22 '22 11:09

Matt Eckert


OK: The following does work on both MSVC and GCC without problems.

The two important errors were:

  • Missing semi-colon in privateRadio.h
  • Including publicRadio.h in radio.c causes double inclusion. It is already included in privateRadio.h

Here is the code I used:

publicRadio.h

    typedef struct _radio Radio;
    void radioReceive(Radio *radio, ....);

privateRadio.h

    #include "publicRadio.h"

    struct _radio {
        ...
        ...
    };

radio.c

    #include "privateRadio.h"

    void radioReceive(Radio *radio, ....)
    {
        ...
    }

main.c

    #include "publicRadio.h"

    void main()
    {
        Radio* radio = ...;
        radioReceive(radio, ....);
    }
like image 26
Kevin A. Naudé Avatar answered Sep 25 '22 11:09

Kevin A. Naudé