简体   繁体   中英

Private struct with property that must be public in .h file in C

I'm working on a library for a user to use and manage with the function prototypes I provide within my header file. Now I have a working hashtable setup in manager.c but I'm at a loss at how to tackle this. I basically want to keep the hashtable "under the hood" from the user by providing them with

typedef struct Manager {
    int size;
    HashList **table;
} Manager;

so they can create this Manager object and use my provided functions to manipulate its contents. However, HashList is declared in my manager.c as

typedef struct HashList {
    /*
     * data stored here
     */
    struct HashList *next;
} HashList;

Now obviously this will not compile as HashList must be in my header file since struct Manager uses HashList. But I do not want HashList to be in the header file as the user shouldn't explicitly have access to this as my functions manipulate the data stored at each hash.

Any advice?

  1. If the user writes: Manager *m = ...; , is it expected that they'll ever write m->xyz ? If not, then you don't need to expose the internals to the end user at all — it is sufficient to provide them with:

     typedef struct Manager Manager; 
  2. If they must dereference the Manager type, it suffices to define:

     typedef struct HashList HashList; 

    in the public header. They don't need to access the insides of that. (Well, if you've any pretensions to providing a concealed service, they have no need for that.)

Between the two options, option 1 is preferable. You provide functions that create and destroy the Manager type, and that allow the user to get or set the size of the structure. With the FILE * type, you don't write code that pokes inside the structure; you just use it via the interface functions you define. You should enforce the same discipline on the users of your code.

Note that if you allow the user to poke at the size element in the Manager structure, you can never tell when they changed it, so you've no idea whether your structure has been corrupted. If you have functional access to it (a get and a set function), you control what happens when the size changes.

You need to make your struct opaque. Keep the implementation details in the library .c files or a private header file and only provide a typedef only.

Example:

library.c

struct SomeStruct
{
    int value;
};

struct SomeStruct *some_struct_alloc()
{
    return malloc(sizeof(SomeStruct)));
}

void some_struct_set_value(struct SomeStruct *someStruct, int value)
{
    if (someStruct != NULL)
        someStruct->value = value;
}

int some_struct_value(struct SomeStruct *someStruct)
{
    if (someStruct != NULL)
        return someStruct->value;
    return SOME_INVALID_VALUE_PERHAPS;
}

library.h

typedef struct SomeStruct SomeStruct;

SomeStruct *some_struct_alloc();
void some_struct_set_value(SomeStruct *someStruct, int value);
int some_struct_value(SomeStruct *someStruct);

program.c

#include <library.h>

int main()
{
    SomeStruct *someStruct;

    someStruct = some_struct_alloc();
    if (someStruct == NULL)
        return -1;
    some_struct_set_value(someStruct, 3);
    printf("%s\n", some_struct_value(someStruct));

    free(someStruct);
    return 0;
}

If the user tries to dereference the someStruct in main() then the compiler would halt with an error similar to dereferencing pointer of incomplete type .

In my opinion, this is a very good way to protect your library's data structure from being misused.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM