Opaque Structure

What is the Handle?

  • The function and concept of the Handle are quite similar to Pointer. As it is known to us, a Pointer can indicate a block of memory and we can ship or visit that memory efficiently. Literally, a well-defined Handle can do the same things as a Pointer. Anyway, we can think of Handle as ID.
  • Usually, a Handle can be defined in such a form: “typedef struct _NAME_T* NAME;”, i.e. a structure pointer. In the 32-bit systems, A Handle can be viewed as uint64, while in the 64-bit systems it is indeed a pointer.
  • Note that we cannot visit the data via handle directly like using a pointer while using Handle. On contrary, we need to utilize ID(Handle) to call some functions, and the function will finish what we want to do implicitly.

What is the Opaque Structure?

  • Opaque Structure is widely utilized in OS. Literally, you can see the Opaque Structure as a C-implement class (Note that C language is not object-orient, but you can make it through many ways, such as Opaque Structure).
  • The most important attribution is the Inaccessibility (like private data in OOP). The client cannot know the details about one Opaque Structure because it is just a block of memory with the same size of pointer for the client, and everything is hidden behind this memory. Therefore, such a design can protect the system security and hide the confidential implement of the system.
  • Now, we know that one Handle is really different from one Pointer, and thus we can use its Data Inaccessibility to implement a Opaque Structure.

Try to Design one Opaque Structure

  • In this section, I design a Time class as a simple example.
  • Commonly, a Handle can be implemented through 2 steps.
  1. Declare a external structure in XXX.h file and typedef it for convenience.
  2. Define that structure in XXX.c.

opaque_time.h

C++
// opaque_time.h
#ifndef __OPAQUE_H__
#define __OPAUQE_H__

extern struct _FrozenTime_T;
typedef struct _FrozenTime_T* FrozenTime;

typedef int Result;

FrozenTime InitTime();
long long GetTimeYear(FrozenTime time);
Result FreeTime(FrozenTime time);

#endif

opaque_time.c

C++
 #include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "opaque_time.h"

typedef struct _FrozenTime_T
{
    time_t sec;
} FrozenTime_T, *FrozenTime;

FrozenTime InitTime()
{
    FrozenTime pTime = (FrozenTime)malloc(sizeof(FrozenTime_T));
    if (pTime == NULL) exit(-1);
    pTime->sec = time(NULL);
    return pTime;
}

long long GetTimeYear(FrozenTime time)
{
    return time->sec / 60 / 60 / 24 / 365; // Not consider leap year
}

int FreeTime(FrozenTime time)
{
    free(time);
}

main.c

C++
#include "opaque_time.h"

#include <stdio.h>

int main()
{
    FrozenTime time = InitTime();
    // [Note]
    // if you want to use time as a pointer (i.e. time->sec) here, 
    // you will make a mistake. And you will not get any prompt if you are using IDE.
    printf("Year since 1970 = %lld\n", GetTimeYear(time));

    FreeTime(time);
    return 0;
}

Conclusion

  • Any time, we can visit the data in one Opaque Structure via its Handle and corresponding functions, just like using Object.xxx() in OOP.
  • Do not mess with Pointer and Handle.
  • We can use the concept of Class as an analogy to Opaque Structure (Unless you want to be deep in pure C programming)

Leave a Reply

Your email address will not be published. Required fields are marked *