How do I hide some fields of struct in C?












9















I'm trying to implement a struct person, and I need to hide some fields or make them constant.
A trick for create private fields.



Header:



#pragma once

#define NAME_MAX_LEN 20

typedef struct _person {
float wage;
int groupid;
} Person;

const char const *getName (Person *p);
int getId (Person *p);

/// OTHER FUNCTIONS


Source



#include "person.h"


struct _person
{
int id;

float wage;
int groupid;

char name[NAME_MAX_LEN];
};

/// FUNCTIONS


GCC says that person.c:7:8: error: redefinition a 'struct _person' struct _person



I can write this in a header, but after it, I can't use fields of a struct.



typedef struct _person Person;









share|improve this question









New contributor




Wootiae is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 9





    C doesn't let you selectively hide fields. There's no private here.

    – user2357112
    Mar 22 at 20:43











  • @user2357112 How to protect from edit my variables (id and name)?

    – Wootiae
    Mar 22 at 20:58






  • 1





    An unusual (not say BOFH) approach to the "no really, just because I let you see the internals doesn't mean it is OK for you to mess with them" problem in a comment elsewhere on the site: stackoverflow.com/questions/31195551/…

    – dmckee
    Mar 23 at 0:37
















9















I'm trying to implement a struct person, and I need to hide some fields or make them constant.
A trick for create private fields.



Header:



#pragma once

#define NAME_MAX_LEN 20

typedef struct _person {
float wage;
int groupid;
} Person;

const char const *getName (Person *p);
int getId (Person *p);

/// OTHER FUNCTIONS


Source



#include "person.h"


struct _person
{
int id;

float wage;
int groupid;

char name[NAME_MAX_LEN];
};

/// FUNCTIONS


GCC says that person.c:7:8: error: redefinition a 'struct _person' struct _person



I can write this in a header, but after it, I can't use fields of a struct.



typedef struct _person Person;









share|improve this question









New contributor




Wootiae is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 9





    C doesn't let you selectively hide fields. There's no private here.

    – user2357112
    Mar 22 at 20:43











  • @user2357112 How to protect from edit my variables (id and name)?

    – Wootiae
    Mar 22 at 20:58






  • 1





    An unusual (not say BOFH) approach to the "no really, just because I let you see the internals doesn't mean it is OK for you to mess with them" problem in a comment elsewhere on the site: stackoverflow.com/questions/31195551/…

    – dmckee
    Mar 23 at 0:37














9












9








9








I'm trying to implement a struct person, and I need to hide some fields or make them constant.
A trick for create private fields.



Header:



#pragma once

#define NAME_MAX_LEN 20

typedef struct _person {
float wage;
int groupid;
} Person;

const char const *getName (Person *p);
int getId (Person *p);

/// OTHER FUNCTIONS


Source



#include "person.h"


struct _person
{
int id;

float wage;
int groupid;

char name[NAME_MAX_LEN];
};

/// FUNCTIONS


GCC says that person.c:7:8: error: redefinition a 'struct _person' struct _person



I can write this in a header, but after it, I can't use fields of a struct.



typedef struct _person Person;









share|improve this question









New contributor




Wootiae is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












I'm trying to implement a struct person, and I need to hide some fields or make them constant.
A trick for create private fields.



Header:



#pragma once

#define NAME_MAX_LEN 20

typedef struct _person {
float wage;
int groupid;
} Person;

const char const *getName (Person *p);
int getId (Person *p);

/// OTHER FUNCTIONS


Source



#include "person.h"


struct _person
{
int id;

float wage;
int groupid;

char name[NAME_MAX_LEN];
};

/// FUNCTIONS


GCC says that person.c:7:8: error: redefinition a 'struct _person' struct _person



I can write this in a header, but after it, I can't use fields of a struct.



typedef struct _person Person;






c typedef






share|improve this question









New contributor




Wootiae is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Wootiae is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited Mar 23 at 15:21









Peter Mortensen

13.8k1987113




13.8k1987113






New contributor




Wootiae is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked Mar 22 at 20:41









WootiaeWootiae

484




484




New contributor




Wootiae is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Wootiae is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Wootiae is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








  • 9





    C doesn't let you selectively hide fields. There's no private here.

    – user2357112
    Mar 22 at 20:43











  • @user2357112 How to protect from edit my variables (id and name)?

    – Wootiae
    Mar 22 at 20:58






  • 1





    An unusual (not say BOFH) approach to the "no really, just because I let you see the internals doesn't mean it is OK for you to mess with them" problem in a comment elsewhere on the site: stackoverflow.com/questions/31195551/…

    – dmckee
    Mar 23 at 0:37














  • 9





    C doesn't let you selectively hide fields. There's no private here.

    – user2357112
    Mar 22 at 20:43











  • @user2357112 How to protect from edit my variables (id and name)?

    – Wootiae
    Mar 22 at 20:58






  • 1





    An unusual (not say BOFH) approach to the "no really, just because I let you see the internals doesn't mean it is OK for you to mess with them" problem in a comment elsewhere on the site: stackoverflow.com/questions/31195551/…

    – dmckee
    Mar 23 at 0:37








9




9





C doesn't let you selectively hide fields. There's no private here.

– user2357112
Mar 22 at 20:43





C doesn't let you selectively hide fields. There's no private here.

– user2357112
Mar 22 at 20:43













@user2357112 How to protect from edit my variables (id and name)?

– Wootiae
Mar 22 at 20:58





@user2357112 How to protect from edit my variables (id and name)?

– Wootiae
Mar 22 at 20:58




1




1





An unusual (not say BOFH) approach to the "no really, just because I let you see the internals doesn't mean it is OK for you to mess with them" problem in a comment elsewhere on the site: stackoverflow.com/questions/31195551/…

– dmckee
Mar 23 at 0:37





An unusual (not say BOFH) approach to the "no really, just because I let you see the internals doesn't mean it is OK for you to mess with them" problem in a comment elsewhere on the site: stackoverflow.com/questions/31195551/…

– dmckee
Mar 23 at 0:37












4 Answers
4






active

oldest

votes


















8














C has no mechanism for hiding individual members of a structure type. However, by operating only in terms of pointers to such a type, and not providing a definition, you can make the whole type opaque. Users would then have to use the functions you provide to manipulate instances in any way. This is a thing that is sometimes done.



To some extent, you may be able to achieve something like what you describe with a hidden context. For example, consider this:



header.h



typedef struct _person {
float wage;
int groupid;
} Person;


implementation.c



struct _person_real {
Person person; // must be first, and is a structure, not a pointer.
int id;
char name[NAME_MAX_LEN];
};


Now you can do this:



Person *create_person(char name) {
struct _person_real *pr = malloc(sizeof(*pr));

if (pr) {
pr->person.wage = DEFAULT_WAGE;
pr->person.groupid = DEFAULT_GROUPID;
pr->id = generate_id();
strncpy(pr->name, name, sizeof(pr->name));
pr->name[sizeof(pr->name) - 1] = '';

return &pr->person; // <-- NOTE WELL
} else {
return NULL;
}
}


A pointer to the first member of a structure always points also to the whole structure, too, so if the client passes a pointer obtained from that function back to you, you can



struct _person_real *pr = (struct _person_real *) Person_pointer;


and work on the members from the larger context.



Be well aware, however, that such a scheme is risky. Nothing prevents a user from creating a Person without the larger context, and passing a pointer to it to a function that expects the context object to be present. There are other issues.



Overall, C APIs generally either take the opaque structure approach or just carefully document what clients are permitted to do with the data they have access to, or even just document how everything works, so that users can make their own choices. These, especially the latter, are well aligned with overall C approaches and idioms -- C does not hold your hand, or protect you from doing harm. It trusts you to know what you're doing, and to do only what you intend to do.






share|improve this answer
























  • just document how everything works, so that users can make their own choices. The problem with that is you become locked into a specific implementation of your structure - which can only be a bad thing. If you miss something in your implementation, or your implementation precludes some new functionality you didn't think of when you designed it, you likely can only make a change if you're willing to break user's code.

    – Andrew Henle
    Mar 22 at 22:37






  • 1





    Better to use a fully opaque pointer anyway so the user doesn't try allocating their own Person.

    – Kevin
    Mar 22 at 23:52



















20














A struct cannot have multiple conflicting definitions. As such, you can't create a struct that hides some of the fields.



What you can do however it declare that the struct exists in the header without defining it. Then the caller is restricted to using only a pointer to the struct and using functions in your implementation to modify it.



For example, you could define your header as follows:



typedef struct _person Person;

Person *init(const char *name, int id, float wage, int groupid);

const char *getName (const Person *p);
int getId (const Person *p);
float getWage (const Person *p);
int getGroupid (const Person *p);


And your implementation would contain:



#include "person.h"

struct _person
{
int id;

float wage;
int groupid;

char name[NAME_MAX_LEN];
};

Person *init(const char *name, int id, float wage, int groupid)
{
Person *p = malloc(sizeof *p);
strcpy(p->name, name);
p->id = id;
p->wage= wage;
p->groupid= groupid;
return p;
}

...





share|improve this answer


























  • I would add const pointers: int getId (const Person *p); so functions can be called with constant pointers (since they're just getters)

    – Jean-François Fabre
    Mar 22 at 20:54






  • 1





    @Jean-FrançoisFabre Good idea. Updated. Also, congrats on the diamond!

    – dbush
    Mar 22 at 20:56











  • Can I "show" wage and groupid? for use p->wage?

    – Wootiae
    Mar 22 at 21:00











  • @Wootiae Not in the calling code, because it doesn't know what Person contains. Your implementation needs an accessor function to allow the user to read it.

    – dbush
    Mar 22 at 21:02











  • How to use sizeof with it?

    – Wootiae
    Mar 22 at 21:10



















2














You can use a mixin style; e.g. write in the header:



struct person {
float wage;
int groupid;
};

struct person *person_new(void);
char const *getName (struct person const *p);
int getId (struct person const *p);


and in the source



struct person_impl {
struct person p;
char name[NAME_MAX_LEN];
int id;
}

struct person *person_new(void)
{
struct person_impl *p;

p = malloc(sizeof *p);
...
return &p->p;
}

chra const *getName(struct person const *p_)
{
struct person_impl *p =
container_of(p_, struct person_impl, p);

return p->name;
}


See e.g. https://en.wikipedia.org/wiki/Offsetof for details of container_of().






share|improve this answer
























  • But then if the caller ever does anything with the returned struct person * other than getting fields with -> the hidden name and id will be lost and getName will return garbage. C won't realize that that is invalid at all.

    – pbfy0
    Mar 23 at 3:18











  • @pbfy0 I do not see a problem here; you can do this everywhere in C. E.g. with the opaque pointer from the other answer you can override internals with memset(persion, 23, 42).

    – ensc
    Mar 23 at 14:02











  • Person a = *person_new(); That code doesn't seem that unreasonable to C users who aren't super experienced. memseting a random offset into the structure seems like a more obvious trigger of unwanted behavaior

    – pbfy0
    Mar 23 at 18:28





















0














What John Bollinger wrote is a neat way of utilising how structs and memory works, but it's also an easy way to get a segfault (imagine allocating an array of Person and then later passing the last element to a 'method' which accesses the id or it's name), or corrupt your data (in an array of Person the next Person is overwriting 'private' variables of the previous Person). You'd have to remember that you must create an array of pointers to Person instead of array of Person (sounds pretty obvious until you decide to optimise something and think that you can allocate and initialise the struct more efficiently than the initialiser function).



Don't get me wrong, it's a great way to solve the problem, but you've got to be careful when using it.
What I'd suggest (though using 4/8 bytes more memory per Person) is to create a struct Person which has a pointer to another struct which is only defined in the .c file and holds the private data. That way it'd be harder to make a mistake somewhere (and if it's a bigger project then trust me - you'll do it sooner or later).



.h file:



#pragma once

#define NAME_MAX_LEN 20

typedef struct _person {
float wage;
int groupid;

__personPriv *const priv;
} Person;

void personInit(Person *p, const char *name);
Person* personNew(const char *name);

const char const *getName (Person *p);
int getId (Person *p);


.c file:



typedef struct {
int id;
char name[NAME_MAX_LEN];
} __personPriv;

const char const *getName (Person *p) {
return p->priv->name;
}

int getId (Person *p) {
return p->priv->id;
}

__personPriv* __personPrivNew(const char *name) {
__personPriv *ret = memcpy(
malloc(sizeof(*ret->priv)),
&(__personPriv) {
.id = generateId();
},
sizeof(*ret->priv)
);

// if(strlen(name) >= NAME_MAX_LEN) {
// raise an error or something?
// return NULL;
// }

strncpy(ret->name, name, strlen(name));

return ret;
}

void personInit(Person *p, const char *name) {
if(p == NULL)
return;

p->priv = memcpy(
malloc(sizeof(*p->priv)),
&(__personPriv) {
.id = generateId();
},
sizeof(*p->priv)
);

ret->priv = __personPrivNew(name);
if(ret->priv == NULL) {
// raise an error or something
}
}

Person* personNew(const char *name) {
Person *ret = malloc(sizeof(*ret));

ret->priv = __personPrivNew(name);
if(ret->priv == NULL) {
free(ret);
return NULL;
}
return ret;
}


Side note: this version can be implemented so that private block is allocated right after/before the 'public' part of the struct to improve locality. Just allocate sizeof(Person) + sizeof(__personPriv) and initialise one part as Person and second one as __personPriv.






share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });






    Wootiae is a new contributor. Be nice, and check out our Code of Conduct.










    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55307489%2fhow-do-i-hide-some-fields-of-struct-in-c%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    8














    C has no mechanism for hiding individual members of a structure type. However, by operating only in terms of pointers to such a type, and not providing a definition, you can make the whole type opaque. Users would then have to use the functions you provide to manipulate instances in any way. This is a thing that is sometimes done.



    To some extent, you may be able to achieve something like what you describe with a hidden context. For example, consider this:



    header.h



    typedef struct _person {
    float wage;
    int groupid;
    } Person;


    implementation.c



    struct _person_real {
    Person person; // must be first, and is a structure, not a pointer.
    int id;
    char name[NAME_MAX_LEN];
    };


    Now you can do this:



    Person *create_person(char name) {
    struct _person_real *pr = malloc(sizeof(*pr));

    if (pr) {
    pr->person.wage = DEFAULT_WAGE;
    pr->person.groupid = DEFAULT_GROUPID;
    pr->id = generate_id();
    strncpy(pr->name, name, sizeof(pr->name));
    pr->name[sizeof(pr->name) - 1] = '';

    return &pr->person; // <-- NOTE WELL
    } else {
    return NULL;
    }
    }


    A pointer to the first member of a structure always points also to the whole structure, too, so if the client passes a pointer obtained from that function back to you, you can



    struct _person_real *pr = (struct _person_real *) Person_pointer;


    and work on the members from the larger context.



    Be well aware, however, that such a scheme is risky. Nothing prevents a user from creating a Person without the larger context, and passing a pointer to it to a function that expects the context object to be present. There are other issues.



    Overall, C APIs generally either take the opaque structure approach or just carefully document what clients are permitted to do with the data they have access to, or even just document how everything works, so that users can make their own choices. These, especially the latter, are well aligned with overall C approaches and idioms -- C does not hold your hand, or protect you from doing harm. It trusts you to know what you're doing, and to do only what you intend to do.






    share|improve this answer
























    • just document how everything works, so that users can make their own choices. The problem with that is you become locked into a specific implementation of your structure - which can only be a bad thing. If you miss something in your implementation, or your implementation precludes some new functionality you didn't think of when you designed it, you likely can only make a change if you're willing to break user's code.

      – Andrew Henle
      Mar 22 at 22:37






    • 1





      Better to use a fully opaque pointer anyway so the user doesn't try allocating their own Person.

      – Kevin
      Mar 22 at 23:52
















    8














    C has no mechanism for hiding individual members of a structure type. However, by operating only in terms of pointers to such a type, and not providing a definition, you can make the whole type opaque. Users would then have to use the functions you provide to manipulate instances in any way. This is a thing that is sometimes done.



    To some extent, you may be able to achieve something like what you describe with a hidden context. For example, consider this:



    header.h



    typedef struct _person {
    float wage;
    int groupid;
    } Person;


    implementation.c



    struct _person_real {
    Person person; // must be first, and is a structure, not a pointer.
    int id;
    char name[NAME_MAX_LEN];
    };


    Now you can do this:



    Person *create_person(char name) {
    struct _person_real *pr = malloc(sizeof(*pr));

    if (pr) {
    pr->person.wage = DEFAULT_WAGE;
    pr->person.groupid = DEFAULT_GROUPID;
    pr->id = generate_id();
    strncpy(pr->name, name, sizeof(pr->name));
    pr->name[sizeof(pr->name) - 1] = '';

    return &pr->person; // <-- NOTE WELL
    } else {
    return NULL;
    }
    }


    A pointer to the first member of a structure always points also to the whole structure, too, so if the client passes a pointer obtained from that function back to you, you can



    struct _person_real *pr = (struct _person_real *) Person_pointer;


    and work on the members from the larger context.



    Be well aware, however, that such a scheme is risky. Nothing prevents a user from creating a Person without the larger context, and passing a pointer to it to a function that expects the context object to be present. There are other issues.



    Overall, C APIs generally either take the opaque structure approach or just carefully document what clients are permitted to do with the data they have access to, or even just document how everything works, so that users can make their own choices. These, especially the latter, are well aligned with overall C approaches and idioms -- C does not hold your hand, or protect you from doing harm. It trusts you to know what you're doing, and to do only what you intend to do.






    share|improve this answer
























    • just document how everything works, so that users can make their own choices. The problem with that is you become locked into a specific implementation of your structure - which can only be a bad thing. If you miss something in your implementation, or your implementation precludes some new functionality you didn't think of when you designed it, you likely can only make a change if you're willing to break user's code.

      – Andrew Henle
      Mar 22 at 22:37






    • 1





      Better to use a fully opaque pointer anyway so the user doesn't try allocating their own Person.

      – Kevin
      Mar 22 at 23:52














    8












    8








    8







    C has no mechanism for hiding individual members of a structure type. However, by operating only in terms of pointers to such a type, and not providing a definition, you can make the whole type opaque. Users would then have to use the functions you provide to manipulate instances in any way. This is a thing that is sometimes done.



    To some extent, you may be able to achieve something like what you describe with a hidden context. For example, consider this:



    header.h



    typedef struct _person {
    float wage;
    int groupid;
    } Person;


    implementation.c



    struct _person_real {
    Person person; // must be first, and is a structure, not a pointer.
    int id;
    char name[NAME_MAX_LEN];
    };


    Now you can do this:



    Person *create_person(char name) {
    struct _person_real *pr = malloc(sizeof(*pr));

    if (pr) {
    pr->person.wage = DEFAULT_WAGE;
    pr->person.groupid = DEFAULT_GROUPID;
    pr->id = generate_id();
    strncpy(pr->name, name, sizeof(pr->name));
    pr->name[sizeof(pr->name) - 1] = '';

    return &pr->person; // <-- NOTE WELL
    } else {
    return NULL;
    }
    }


    A pointer to the first member of a structure always points also to the whole structure, too, so if the client passes a pointer obtained from that function back to you, you can



    struct _person_real *pr = (struct _person_real *) Person_pointer;


    and work on the members from the larger context.



    Be well aware, however, that such a scheme is risky. Nothing prevents a user from creating a Person without the larger context, and passing a pointer to it to a function that expects the context object to be present. There are other issues.



    Overall, C APIs generally either take the opaque structure approach or just carefully document what clients are permitted to do with the data they have access to, or even just document how everything works, so that users can make their own choices. These, especially the latter, are well aligned with overall C approaches and idioms -- C does not hold your hand, or protect you from doing harm. It trusts you to know what you're doing, and to do only what you intend to do.






    share|improve this answer













    C has no mechanism for hiding individual members of a structure type. However, by operating only in terms of pointers to such a type, and not providing a definition, you can make the whole type opaque. Users would then have to use the functions you provide to manipulate instances in any way. This is a thing that is sometimes done.



    To some extent, you may be able to achieve something like what you describe with a hidden context. For example, consider this:



    header.h



    typedef struct _person {
    float wage;
    int groupid;
    } Person;


    implementation.c



    struct _person_real {
    Person person; // must be first, and is a structure, not a pointer.
    int id;
    char name[NAME_MAX_LEN];
    };


    Now you can do this:



    Person *create_person(char name) {
    struct _person_real *pr = malloc(sizeof(*pr));

    if (pr) {
    pr->person.wage = DEFAULT_WAGE;
    pr->person.groupid = DEFAULT_GROUPID;
    pr->id = generate_id();
    strncpy(pr->name, name, sizeof(pr->name));
    pr->name[sizeof(pr->name) - 1] = '';

    return &pr->person; // <-- NOTE WELL
    } else {
    return NULL;
    }
    }


    A pointer to the first member of a structure always points also to the whole structure, too, so if the client passes a pointer obtained from that function back to you, you can



    struct _person_real *pr = (struct _person_real *) Person_pointer;


    and work on the members from the larger context.



    Be well aware, however, that such a scheme is risky. Nothing prevents a user from creating a Person without the larger context, and passing a pointer to it to a function that expects the context object to be present. There are other issues.



    Overall, C APIs generally either take the opaque structure approach or just carefully document what clients are permitted to do with the data they have access to, or even just document how everything works, so that users can make their own choices. These, especially the latter, are well aligned with overall C approaches and idioms -- C does not hold your hand, or protect you from doing harm. It trusts you to know what you're doing, and to do only what you intend to do.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Mar 22 at 21:04









    John BollingerJohn Bollinger

    84.3k74279




    84.3k74279













    • just document how everything works, so that users can make their own choices. The problem with that is you become locked into a specific implementation of your structure - which can only be a bad thing. If you miss something in your implementation, or your implementation precludes some new functionality you didn't think of when you designed it, you likely can only make a change if you're willing to break user's code.

      – Andrew Henle
      Mar 22 at 22:37






    • 1





      Better to use a fully opaque pointer anyway so the user doesn't try allocating their own Person.

      – Kevin
      Mar 22 at 23:52



















    • just document how everything works, so that users can make their own choices. The problem with that is you become locked into a specific implementation of your structure - which can only be a bad thing. If you miss something in your implementation, or your implementation precludes some new functionality you didn't think of when you designed it, you likely can only make a change if you're willing to break user's code.

      – Andrew Henle
      Mar 22 at 22:37






    • 1





      Better to use a fully opaque pointer anyway so the user doesn't try allocating their own Person.

      – Kevin
      Mar 22 at 23:52

















    just document how everything works, so that users can make their own choices. The problem with that is you become locked into a specific implementation of your structure - which can only be a bad thing. If you miss something in your implementation, or your implementation precludes some new functionality you didn't think of when you designed it, you likely can only make a change if you're willing to break user's code.

    – Andrew Henle
    Mar 22 at 22:37





    just document how everything works, so that users can make their own choices. The problem with that is you become locked into a specific implementation of your structure - which can only be a bad thing. If you miss something in your implementation, or your implementation precludes some new functionality you didn't think of when you designed it, you likely can only make a change if you're willing to break user's code.

    – Andrew Henle
    Mar 22 at 22:37




    1




    1





    Better to use a fully opaque pointer anyway so the user doesn't try allocating their own Person.

    – Kevin
    Mar 22 at 23:52





    Better to use a fully opaque pointer anyway so the user doesn't try allocating their own Person.

    – Kevin
    Mar 22 at 23:52













    20














    A struct cannot have multiple conflicting definitions. As such, you can't create a struct that hides some of the fields.



    What you can do however it declare that the struct exists in the header without defining it. Then the caller is restricted to using only a pointer to the struct and using functions in your implementation to modify it.



    For example, you could define your header as follows:



    typedef struct _person Person;

    Person *init(const char *name, int id, float wage, int groupid);

    const char *getName (const Person *p);
    int getId (const Person *p);
    float getWage (const Person *p);
    int getGroupid (const Person *p);


    And your implementation would contain:



    #include "person.h"

    struct _person
    {
    int id;

    float wage;
    int groupid;

    char name[NAME_MAX_LEN];
    };

    Person *init(const char *name, int id, float wage, int groupid)
    {
    Person *p = malloc(sizeof *p);
    strcpy(p->name, name);
    p->id = id;
    p->wage= wage;
    p->groupid= groupid;
    return p;
    }

    ...





    share|improve this answer


























    • I would add const pointers: int getId (const Person *p); so functions can be called with constant pointers (since they're just getters)

      – Jean-François Fabre
      Mar 22 at 20:54






    • 1





      @Jean-FrançoisFabre Good idea. Updated. Also, congrats on the diamond!

      – dbush
      Mar 22 at 20:56











    • Can I "show" wage and groupid? for use p->wage?

      – Wootiae
      Mar 22 at 21:00











    • @Wootiae Not in the calling code, because it doesn't know what Person contains. Your implementation needs an accessor function to allow the user to read it.

      – dbush
      Mar 22 at 21:02











    • How to use sizeof with it?

      – Wootiae
      Mar 22 at 21:10
















    20














    A struct cannot have multiple conflicting definitions. As such, you can't create a struct that hides some of the fields.



    What you can do however it declare that the struct exists in the header without defining it. Then the caller is restricted to using only a pointer to the struct and using functions in your implementation to modify it.



    For example, you could define your header as follows:



    typedef struct _person Person;

    Person *init(const char *name, int id, float wage, int groupid);

    const char *getName (const Person *p);
    int getId (const Person *p);
    float getWage (const Person *p);
    int getGroupid (const Person *p);


    And your implementation would contain:



    #include "person.h"

    struct _person
    {
    int id;

    float wage;
    int groupid;

    char name[NAME_MAX_LEN];
    };

    Person *init(const char *name, int id, float wage, int groupid)
    {
    Person *p = malloc(sizeof *p);
    strcpy(p->name, name);
    p->id = id;
    p->wage= wage;
    p->groupid= groupid;
    return p;
    }

    ...





    share|improve this answer


























    • I would add const pointers: int getId (const Person *p); so functions can be called with constant pointers (since they're just getters)

      – Jean-François Fabre
      Mar 22 at 20:54






    • 1





      @Jean-FrançoisFabre Good idea. Updated. Also, congrats on the diamond!

      – dbush
      Mar 22 at 20:56











    • Can I "show" wage and groupid? for use p->wage?

      – Wootiae
      Mar 22 at 21:00











    • @Wootiae Not in the calling code, because it doesn't know what Person contains. Your implementation needs an accessor function to allow the user to read it.

      – dbush
      Mar 22 at 21:02











    • How to use sizeof with it?

      – Wootiae
      Mar 22 at 21:10














    20












    20








    20







    A struct cannot have multiple conflicting definitions. As such, you can't create a struct that hides some of the fields.



    What you can do however it declare that the struct exists in the header without defining it. Then the caller is restricted to using only a pointer to the struct and using functions in your implementation to modify it.



    For example, you could define your header as follows:



    typedef struct _person Person;

    Person *init(const char *name, int id, float wage, int groupid);

    const char *getName (const Person *p);
    int getId (const Person *p);
    float getWage (const Person *p);
    int getGroupid (const Person *p);


    And your implementation would contain:



    #include "person.h"

    struct _person
    {
    int id;

    float wage;
    int groupid;

    char name[NAME_MAX_LEN];
    };

    Person *init(const char *name, int id, float wage, int groupid)
    {
    Person *p = malloc(sizeof *p);
    strcpy(p->name, name);
    p->id = id;
    p->wage= wage;
    p->groupid= groupid;
    return p;
    }

    ...





    share|improve this answer















    A struct cannot have multiple conflicting definitions. As such, you can't create a struct that hides some of the fields.



    What you can do however it declare that the struct exists in the header without defining it. Then the caller is restricted to using only a pointer to the struct and using functions in your implementation to modify it.



    For example, you could define your header as follows:



    typedef struct _person Person;

    Person *init(const char *name, int id, float wage, int groupid);

    const char *getName (const Person *p);
    int getId (const Person *p);
    float getWage (const Person *p);
    int getGroupid (const Person *p);


    And your implementation would contain:



    #include "person.h"

    struct _person
    {
    int id;

    float wage;
    int groupid;

    char name[NAME_MAX_LEN];
    };

    Person *init(const char *name, int id, float wage, int groupid)
    {
    Person *p = malloc(sizeof *p);
    strcpy(p->name, name);
    p->id = id;
    p->wage= wage;
    p->groupid= groupid;
    return p;
    }

    ...






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Mar 22 at 21:04

























    answered Mar 22 at 20:48









    dbushdbush

    103k13108145




    103k13108145













    • I would add const pointers: int getId (const Person *p); so functions can be called with constant pointers (since they're just getters)

      – Jean-François Fabre
      Mar 22 at 20:54






    • 1





      @Jean-FrançoisFabre Good idea. Updated. Also, congrats on the diamond!

      – dbush
      Mar 22 at 20:56











    • Can I "show" wage and groupid? for use p->wage?

      – Wootiae
      Mar 22 at 21:00











    • @Wootiae Not in the calling code, because it doesn't know what Person contains. Your implementation needs an accessor function to allow the user to read it.

      – dbush
      Mar 22 at 21:02











    • How to use sizeof with it?

      – Wootiae
      Mar 22 at 21:10



















    • I would add const pointers: int getId (const Person *p); so functions can be called with constant pointers (since they're just getters)

      – Jean-François Fabre
      Mar 22 at 20:54






    • 1





      @Jean-FrançoisFabre Good idea. Updated. Also, congrats on the diamond!

      – dbush
      Mar 22 at 20:56











    • Can I "show" wage and groupid? for use p->wage?

      – Wootiae
      Mar 22 at 21:00











    • @Wootiae Not in the calling code, because it doesn't know what Person contains. Your implementation needs an accessor function to allow the user to read it.

      – dbush
      Mar 22 at 21:02











    • How to use sizeof with it?

      – Wootiae
      Mar 22 at 21:10

















    I would add const pointers: int getId (const Person *p); so functions can be called with constant pointers (since they're just getters)

    – Jean-François Fabre
    Mar 22 at 20:54





    I would add const pointers: int getId (const Person *p); so functions can be called with constant pointers (since they're just getters)

    – Jean-François Fabre
    Mar 22 at 20:54




    1




    1





    @Jean-FrançoisFabre Good idea. Updated. Also, congrats on the diamond!

    – dbush
    Mar 22 at 20:56





    @Jean-FrançoisFabre Good idea. Updated. Also, congrats on the diamond!

    – dbush
    Mar 22 at 20:56













    Can I "show" wage and groupid? for use p->wage?

    – Wootiae
    Mar 22 at 21:00





    Can I "show" wage and groupid? for use p->wage?

    – Wootiae
    Mar 22 at 21:00













    @Wootiae Not in the calling code, because it doesn't know what Person contains. Your implementation needs an accessor function to allow the user to read it.

    – dbush
    Mar 22 at 21:02





    @Wootiae Not in the calling code, because it doesn't know what Person contains. Your implementation needs an accessor function to allow the user to read it.

    – dbush
    Mar 22 at 21:02













    How to use sizeof with it?

    – Wootiae
    Mar 22 at 21:10





    How to use sizeof with it?

    – Wootiae
    Mar 22 at 21:10











    2














    You can use a mixin style; e.g. write in the header:



    struct person {
    float wage;
    int groupid;
    };

    struct person *person_new(void);
    char const *getName (struct person const *p);
    int getId (struct person const *p);


    and in the source



    struct person_impl {
    struct person p;
    char name[NAME_MAX_LEN];
    int id;
    }

    struct person *person_new(void)
    {
    struct person_impl *p;

    p = malloc(sizeof *p);
    ...
    return &p->p;
    }

    chra const *getName(struct person const *p_)
    {
    struct person_impl *p =
    container_of(p_, struct person_impl, p);

    return p->name;
    }


    See e.g. https://en.wikipedia.org/wiki/Offsetof for details of container_of().






    share|improve this answer
























    • But then if the caller ever does anything with the returned struct person * other than getting fields with -> the hidden name and id will be lost and getName will return garbage. C won't realize that that is invalid at all.

      – pbfy0
      Mar 23 at 3:18











    • @pbfy0 I do not see a problem here; you can do this everywhere in C. E.g. with the opaque pointer from the other answer you can override internals with memset(persion, 23, 42).

      – ensc
      Mar 23 at 14:02











    • Person a = *person_new(); That code doesn't seem that unreasonable to C users who aren't super experienced. memseting a random offset into the structure seems like a more obvious trigger of unwanted behavaior

      – pbfy0
      Mar 23 at 18:28


















    2














    You can use a mixin style; e.g. write in the header:



    struct person {
    float wage;
    int groupid;
    };

    struct person *person_new(void);
    char const *getName (struct person const *p);
    int getId (struct person const *p);


    and in the source



    struct person_impl {
    struct person p;
    char name[NAME_MAX_LEN];
    int id;
    }

    struct person *person_new(void)
    {
    struct person_impl *p;

    p = malloc(sizeof *p);
    ...
    return &p->p;
    }

    chra const *getName(struct person const *p_)
    {
    struct person_impl *p =
    container_of(p_, struct person_impl, p);

    return p->name;
    }


    See e.g. https://en.wikipedia.org/wiki/Offsetof for details of container_of().






    share|improve this answer
























    • But then if the caller ever does anything with the returned struct person * other than getting fields with -> the hidden name and id will be lost and getName will return garbage. C won't realize that that is invalid at all.

      – pbfy0
      Mar 23 at 3:18











    • @pbfy0 I do not see a problem here; you can do this everywhere in C. E.g. with the opaque pointer from the other answer you can override internals with memset(persion, 23, 42).

      – ensc
      Mar 23 at 14:02











    • Person a = *person_new(); That code doesn't seem that unreasonable to C users who aren't super experienced. memseting a random offset into the structure seems like a more obvious trigger of unwanted behavaior

      – pbfy0
      Mar 23 at 18:28
















    2












    2








    2







    You can use a mixin style; e.g. write in the header:



    struct person {
    float wage;
    int groupid;
    };

    struct person *person_new(void);
    char const *getName (struct person const *p);
    int getId (struct person const *p);


    and in the source



    struct person_impl {
    struct person p;
    char name[NAME_MAX_LEN];
    int id;
    }

    struct person *person_new(void)
    {
    struct person_impl *p;

    p = malloc(sizeof *p);
    ...
    return &p->p;
    }

    chra const *getName(struct person const *p_)
    {
    struct person_impl *p =
    container_of(p_, struct person_impl, p);

    return p->name;
    }


    See e.g. https://en.wikipedia.org/wiki/Offsetof for details of container_of().






    share|improve this answer













    You can use a mixin style; e.g. write in the header:



    struct person {
    float wage;
    int groupid;
    };

    struct person *person_new(void);
    char const *getName (struct person const *p);
    int getId (struct person const *p);


    and in the source



    struct person_impl {
    struct person p;
    char name[NAME_MAX_LEN];
    int id;
    }

    struct person *person_new(void)
    {
    struct person_impl *p;

    p = malloc(sizeof *p);
    ...
    return &p->p;
    }

    chra const *getName(struct person const *p_)
    {
    struct person_impl *p =
    container_of(p_, struct person_impl, p);

    return p->name;
    }


    See e.g. https://en.wikipedia.org/wiki/Offsetof for details of container_of().







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Mar 22 at 21:04









    enscensc

    4,491815




    4,491815













    • But then if the caller ever does anything with the returned struct person * other than getting fields with -> the hidden name and id will be lost and getName will return garbage. C won't realize that that is invalid at all.

      – pbfy0
      Mar 23 at 3:18











    • @pbfy0 I do not see a problem here; you can do this everywhere in C. E.g. with the opaque pointer from the other answer you can override internals with memset(persion, 23, 42).

      – ensc
      Mar 23 at 14:02











    • Person a = *person_new(); That code doesn't seem that unreasonable to C users who aren't super experienced. memseting a random offset into the structure seems like a more obvious trigger of unwanted behavaior

      – pbfy0
      Mar 23 at 18:28





















    • But then if the caller ever does anything with the returned struct person * other than getting fields with -> the hidden name and id will be lost and getName will return garbage. C won't realize that that is invalid at all.

      – pbfy0
      Mar 23 at 3:18











    • @pbfy0 I do not see a problem here; you can do this everywhere in C. E.g. with the opaque pointer from the other answer you can override internals with memset(persion, 23, 42).

      – ensc
      Mar 23 at 14:02











    • Person a = *person_new(); That code doesn't seem that unreasonable to C users who aren't super experienced. memseting a random offset into the structure seems like a more obvious trigger of unwanted behavaior

      – pbfy0
      Mar 23 at 18:28



















    But then if the caller ever does anything with the returned struct person * other than getting fields with -> the hidden name and id will be lost and getName will return garbage. C won't realize that that is invalid at all.

    – pbfy0
    Mar 23 at 3:18





    But then if the caller ever does anything with the returned struct person * other than getting fields with -> the hidden name and id will be lost and getName will return garbage. C won't realize that that is invalid at all.

    – pbfy0
    Mar 23 at 3:18













    @pbfy0 I do not see a problem here; you can do this everywhere in C. E.g. with the opaque pointer from the other answer you can override internals with memset(persion, 23, 42).

    – ensc
    Mar 23 at 14:02





    @pbfy0 I do not see a problem here; you can do this everywhere in C. E.g. with the opaque pointer from the other answer you can override internals with memset(persion, 23, 42).

    – ensc
    Mar 23 at 14:02













    Person a = *person_new(); That code doesn't seem that unreasonable to C users who aren't super experienced. memseting a random offset into the structure seems like a more obvious trigger of unwanted behavaior

    – pbfy0
    Mar 23 at 18:28







    Person a = *person_new(); That code doesn't seem that unreasonable to C users who aren't super experienced. memseting a random offset into the structure seems like a more obvious trigger of unwanted behavaior

    – pbfy0
    Mar 23 at 18:28













    0














    What John Bollinger wrote is a neat way of utilising how structs and memory works, but it's also an easy way to get a segfault (imagine allocating an array of Person and then later passing the last element to a 'method' which accesses the id or it's name), or corrupt your data (in an array of Person the next Person is overwriting 'private' variables of the previous Person). You'd have to remember that you must create an array of pointers to Person instead of array of Person (sounds pretty obvious until you decide to optimise something and think that you can allocate and initialise the struct more efficiently than the initialiser function).



    Don't get me wrong, it's a great way to solve the problem, but you've got to be careful when using it.
    What I'd suggest (though using 4/8 bytes more memory per Person) is to create a struct Person which has a pointer to another struct which is only defined in the .c file and holds the private data. That way it'd be harder to make a mistake somewhere (and if it's a bigger project then trust me - you'll do it sooner or later).



    .h file:



    #pragma once

    #define NAME_MAX_LEN 20

    typedef struct _person {
    float wage;
    int groupid;

    __personPriv *const priv;
    } Person;

    void personInit(Person *p, const char *name);
    Person* personNew(const char *name);

    const char const *getName (Person *p);
    int getId (Person *p);


    .c file:



    typedef struct {
    int id;
    char name[NAME_MAX_LEN];
    } __personPriv;

    const char const *getName (Person *p) {
    return p->priv->name;
    }

    int getId (Person *p) {
    return p->priv->id;
    }

    __personPriv* __personPrivNew(const char *name) {
    __personPriv *ret = memcpy(
    malloc(sizeof(*ret->priv)),
    &(__personPriv) {
    .id = generateId();
    },
    sizeof(*ret->priv)
    );

    // if(strlen(name) >= NAME_MAX_LEN) {
    // raise an error or something?
    // return NULL;
    // }

    strncpy(ret->name, name, strlen(name));

    return ret;
    }

    void personInit(Person *p, const char *name) {
    if(p == NULL)
    return;

    p->priv = memcpy(
    malloc(sizeof(*p->priv)),
    &(__personPriv) {
    .id = generateId();
    },
    sizeof(*p->priv)
    );

    ret->priv = __personPrivNew(name);
    if(ret->priv == NULL) {
    // raise an error or something
    }
    }

    Person* personNew(const char *name) {
    Person *ret = malloc(sizeof(*ret));

    ret->priv = __personPrivNew(name);
    if(ret->priv == NULL) {
    free(ret);
    return NULL;
    }
    return ret;
    }


    Side note: this version can be implemented so that private block is allocated right after/before the 'public' part of the struct to improve locality. Just allocate sizeof(Person) + sizeof(__personPriv) and initialise one part as Person and second one as __personPriv.






    share|improve this answer






























      0














      What John Bollinger wrote is a neat way of utilising how structs and memory works, but it's also an easy way to get a segfault (imagine allocating an array of Person and then later passing the last element to a 'method' which accesses the id or it's name), or corrupt your data (in an array of Person the next Person is overwriting 'private' variables of the previous Person). You'd have to remember that you must create an array of pointers to Person instead of array of Person (sounds pretty obvious until you decide to optimise something and think that you can allocate and initialise the struct more efficiently than the initialiser function).



      Don't get me wrong, it's a great way to solve the problem, but you've got to be careful when using it.
      What I'd suggest (though using 4/8 bytes more memory per Person) is to create a struct Person which has a pointer to another struct which is only defined in the .c file and holds the private data. That way it'd be harder to make a mistake somewhere (and if it's a bigger project then trust me - you'll do it sooner or later).



      .h file:



      #pragma once

      #define NAME_MAX_LEN 20

      typedef struct _person {
      float wage;
      int groupid;

      __personPriv *const priv;
      } Person;

      void personInit(Person *p, const char *name);
      Person* personNew(const char *name);

      const char const *getName (Person *p);
      int getId (Person *p);


      .c file:



      typedef struct {
      int id;
      char name[NAME_MAX_LEN];
      } __personPriv;

      const char const *getName (Person *p) {
      return p->priv->name;
      }

      int getId (Person *p) {
      return p->priv->id;
      }

      __personPriv* __personPrivNew(const char *name) {
      __personPriv *ret = memcpy(
      malloc(sizeof(*ret->priv)),
      &(__personPriv) {
      .id = generateId();
      },
      sizeof(*ret->priv)
      );

      // if(strlen(name) >= NAME_MAX_LEN) {
      // raise an error or something?
      // return NULL;
      // }

      strncpy(ret->name, name, strlen(name));

      return ret;
      }

      void personInit(Person *p, const char *name) {
      if(p == NULL)
      return;

      p->priv = memcpy(
      malloc(sizeof(*p->priv)),
      &(__personPriv) {
      .id = generateId();
      },
      sizeof(*p->priv)
      );

      ret->priv = __personPrivNew(name);
      if(ret->priv == NULL) {
      // raise an error or something
      }
      }

      Person* personNew(const char *name) {
      Person *ret = malloc(sizeof(*ret));

      ret->priv = __personPrivNew(name);
      if(ret->priv == NULL) {
      free(ret);
      return NULL;
      }
      return ret;
      }


      Side note: this version can be implemented so that private block is allocated right after/before the 'public' part of the struct to improve locality. Just allocate sizeof(Person) + sizeof(__personPriv) and initialise one part as Person and second one as __personPriv.






      share|improve this answer




























        0












        0








        0







        What John Bollinger wrote is a neat way of utilising how structs and memory works, but it's also an easy way to get a segfault (imagine allocating an array of Person and then later passing the last element to a 'method' which accesses the id or it's name), or corrupt your data (in an array of Person the next Person is overwriting 'private' variables of the previous Person). You'd have to remember that you must create an array of pointers to Person instead of array of Person (sounds pretty obvious until you decide to optimise something and think that you can allocate and initialise the struct more efficiently than the initialiser function).



        Don't get me wrong, it's a great way to solve the problem, but you've got to be careful when using it.
        What I'd suggest (though using 4/8 bytes more memory per Person) is to create a struct Person which has a pointer to another struct which is only defined in the .c file and holds the private data. That way it'd be harder to make a mistake somewhere (and if it's a bigger project then trust me - you'll do it sooner or later).



        .h file:



        #pragma once

        #define NAME_MAX_LEN 20

        typedef struct _person {
        float wage;
        int groupid;

        __personPriv *const priv;
        } Person;

        void personInit(Person *p, const char *name);
        Person* personNew(const char *name);

        const char const *getName (Person *p);
        int getId (Person *p);


        .c file:



        typedef struct {
        int id;
        char name[NAME_MAX_LEN];
        } __personPriv;

        const char const *getName (Person *p) {
        return p->priv->name;
        }

        int getId (Person *p) {
        return p->priv->id;
        }

        __personPriv* __personPrivNew(const char *name) {
        __personPriv *ret = memcpy(
        malloc(sizeof(*ret->priv)),
        &(__personPriv) {
        .id = generateId();
        },
        sizeof(*ret->priv)
        );

        // if(strlen(name) >= NAME_MAX_LEN) {
        // raise an error or something?
        // return NULL;
        // }

        strncpy(ret->name, name, strlen(name));

        return ret;
        }

        void personInit(Person *p, const char *name) {
        if(p == NULL)
        return;

        p->priv = memcpy(
        malloc(sizeof(*p->priv)),
        &(__personPriv) {
        .id = generateId();
        },
        sizeof(*p->priv)
        );

        ret->priv = __personPrivNew(name);
        if(ret->priv == NULL) {
        // raise an error or something
        }
        }

        Person* personNew(const char *name) {
        Person *ret = malloc(sizeof(*ret));

        ret->priv = __personPrivNew(name);
        if(ret->priv == NULL) {
        free(ret);
        return NULL;
        }
        return ret;
        }


        Side note: this version can be implemented so that private block is allocated right after/before the 'public' part of the struct to improve locality. Just allocate sizeof(Person) + sizeof(__personPriv) and initialise one part as Person and second one as __personPriv.






        share|improve this answer















        What John Bollinger wrote is a neat way of utilising how structs and memory works, but it's also an easy way to get a segfault (imagine allocating an array of Person and then later passing the last element to a 'method' which accesses the id or it's name), or corrupt your data (in an array of Person the next Person is overwriting 'private' variables of the previous Person). You'd have to remember that you must create an array of pointers to Person instead of array of Person (sounds pretty obvious until you decide to optimise something and think that you can allocate and initialise the struct more efficiently than the initialiser function).



        Don't get me wrong, it's a great way to solve the problem, but you've got to be careful when using it.
        What I'd suggest (though using 4/8 bytes more memory per Person) is to create a struct Person which has a pointer to another struct which is only defined in the .c file and holds the private data. That way it'd be harder to make a mistake somewhere (and if it's a bigger project then trust me - you'll do it sooner or later).



        .h file:



        #pragma once

        #define NAME_MAX_LEN 20

        typedef struct _person {
        float wage;
        int groupid;

        __personPriv *const priv;
        } Person;

        void personInit(Person *p, const char *name);
        Person* personNew(const char *name);

        const char const *getName (Person *p);
        int getId (Person *p);


        .c file:



        typedef struct {
        int id;
        char name[NAME_MAX_LEN];
        } __personPriv;

        const char const *getName (Person *p) {
        return p->priv->name;
        }

        int getId (Person *p) {
        return p->priv->id;
        }

        __personPriv* __personPrivNew(const char *name) {
        __personPriv *ret = memcpy(
        malloc(sizeof(*ret->priv)),
        &(__personPriv) {
        .id = generateId();
        },
        sizeof(*ret->priv)
        );

        // if(strlen(name) >= NAME_MAX_LEN) {
        // raise an error or something?
        // return NULL;
        // }

        strncpy(ret->name, name, strlen(name));

        return ret;
        }

        void personInit(Person *p, const char *name) {
        if(p == NULL)
        return;

        p->priv = memcpy(
        malloc(sizeof(*p->priv)),
        &(__personPriv) {
        .id = generateId();
        },
        sizeof(*p->priv)
        );

        ret->priv = __personPrivNew(name);
        if(ret->priv == NULL) {
        // raise an error or something
        }
        }

        Person* personNew(const char *name) {
        Person *ret = malloc(sizeof(*ret));

        ret->priv = __personPrivNew(name);
        if(ret->priv == NULL) {
        free(ret);
        return NULL;
        }
        return ret;
        }


        Side note: this version can be implemented so that private block is allocated right after/before the 'public' part of the struct to improve locality. Just allocate sizeof(Person) + sizeof(__personPriv) and initialise one part as Person and second one as __personPriv.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Mar 22 at 23:25

























        answered Mar 22 at 22:29









        GrabuszGrabusz

        4116




        4116






















            Wootiae is a new contributor. Be nice, and check out our Code of Conduct.










            draft saved

            draft discarded


















            Wootiae is a new contributor. Be nice, and check out our Code of Conduct.













            Wootiae is a new contributor. Be nice, and check out our Code of Conduct.












            Wootiae is a new contributor. Be nice, and check out our Code of Conduct.
















            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55307489%2fhow-do-i-hide-some-fields-of-struct-in-c%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Plaza Victoria

            Puebla de Zaragoza

            Musa