Hi Alexandre, > Is that true? I wouldn't do it that way, but that's one way to do it. I'd do it this way: Foo.h struct CW_C_MsgUp_s; typedef struct CW_C_MsgUp_s* CW_C_MsgUp_t; CW_C_MsgUp_t CW_C_MsgUp_new(); void CW_C_MsgUp_delete(CW_C_MsgUp_t); struct CW_C_MsgDown_s; typedef struct CW_C_MsgDown_s* CW_C_MsgDown_t; CW_C_MsgDown_t CW_C_MsgDown_new(); void CW_C_MsgDown_delete(CW_C_MsgDown_t); private/FooImpl.h struct CW_C_MsgUp_s { int refCount; int value; int anotherValue; int somethingElse; double bigValue; char* someRelevantString; // Could be NULL. }; struct CW_C_MsgDown_s { int refCount; double x; double y; double z; int active; }; private/Foo.c #include "Foo.h" #include "FooImpl.h" // The function implementations. Where libFoo.a and Foo.h are shipped to customers. And private/FooImpl.h and private/Foo.c are not shipped to customers. > Why did you talk about a "reference counting mechanism"? When working with opaque types, having a reference count can make working with the item much more convenient for the end-user. You don't have to provide such a mechanism. Having reference counts is not necessary; it's only useful in some domains. Usually depending on how the items are used. > Because in my implementation my C "constructor" and "destructor" functions do not have any counting mechanism, is that a problem. No, it's not necessarily a problem. Depends on how the items are used. > Actually, I rely on the users/callers of the functions to call the "destructor" as many times as the "constructor", avoiding memory losses. That's good. That way your heap management may (or may not) be separate from the heap management of the user side. Having the possibility of it being separate can be a very good thing, in some circumstances. > But, if you talked about a "reference counting mechanism", is it to prevent memory leaks? A reference counting mechanism cannot prevent memory leaks. A user could still "construct" an item, and neglect to release it (hence, decrementing its reference count, and destruct the item when the count hits zero). A reference counting mechanism is a convenience for the users of your items. Which, depending on the usage pattern, may-or-may-not be useful. > By implementing a kind of basic "garbage collector", destroying undeleted allocated structures? Is that what you meant? No, a reference counting mechanism is not a basic garbage collector. Those are different technologies. (Although a basic garbage collector could use reference counting itself as its own mechanism, which introduces certain problems.) The difference between the two is in a garbage collector, the user does not have to worry about reference counts or releasing -- that's the garbage collector's job. > Yes and no. Because if it will or will not be confused with such a typedef. If you use (note that the typedef is not a pointer)... typedef struct CW_C_MsgUp_s CW_C_MsgUp_t; ...then you are pretty much allowing (requiring) that your structure be visible, which means it is not opaque. And beyond that, you are definitely putting a burden on the users of your type to comply with your constraints in their code, rather then putting your constraints in the type itself. If you use (note that the typedef is a pointer)... typedef struct CW_C_MsgUp_s* CW_C_MsgUp_t; ...then you are able to make your structure opaque (i.e., in your private header file, as an implementation detail; one that can be changed when the underlying implementation rev's). > Because my "*_new" and "*_delete" functions will allocate and destroy objects > (structures, classes, int, char buf, etc, who knows, that doesn't matter) and > the allocation function on failure can return a null pointer. Therefore how > will the caller test the returned value (not considered as pointer because of > typedef) with null? The typedef *IS* a pointer. The caller can test the returned value with NULL. struct CW_C_MsgUp_s; // Forward declare. typedef struct CW_C_MsgUp_s* CW_C_MsgUp_t; // CW_C_MsgUp_t *IS* a pointer! CW_C_MsgUp_t my_up_msg = NULL; my_up_msg = CW_C_MsgUp_new(); if(my_up_msg == NULL) { return -1; } > I think a workaround could be to pass the "my_up_msg" or "my_down_msg" > variables as parameter of "*_new" functions and test an integer returned value > of "*_new", telling how everything goes? I would not implement it that way. > Which of example1 and example2 is better to use? example1, in my opinion. > On the same kind of reflexion, how do I have to initialize my_up_msg? > 1. my_up_msg = 0; > 2. my_up_msg = null; > 3. memset(my_up_msg, 0, sizeof(my_up_msg))? > 4. memset(&my_up_msg, 0, sizeof(my_up_msg))? I would use a fifth way: my_up_msg = NULL; I would not introduce a lower-case identifier 'null'. > The solution I feel is the good one are 2 and 4, but they mean that I do not avoid the fact that "my_up_msg" is a typedef-ed pointer. Correct. You do not avoid the fact that "my_up_msg" is a typedef-ed pointer. You know it, your users know it. You rely on it, your users rely on it. The important bit is that my_up_msg is a TYPED pointer (hence, the type-safety you are trying to obtain), and it also points to an OPAQUE structure which is not provided in the public headers (hence, the users cannot manipulate it or observe it behind your back, and you can change the backing store structure without concerns about breaking user's code). > How could I do to not confuse the users and me? Documentation. Perhaps adapt the Hungarian-ish convention of using '_p' or '_ptr' (meaning "pointer"), or if you use reference counting '_r' or '_ref' (meaning "reference"), instead of '_t' (meaning "type") for the identifier suffix. Carbon tends to use the suffix 'Ref' (meaning "reference"). So they have CFStringRef, CFAllocatorRef, CFArrayRef, et cetera. The "CF" prefix in this case stands for CoreFoundation, which is one of Apple's frameworks (Apple's term for what I'd call a SDK). Whatever the convention you adopt, I strongly recommend consistency. > I'm aware that this solution is very interesting because it does not allow people to dereference the variable. That's the OPAQUE part, which is very nice to have in a SDK. > But is that a recommended coding rule? It is a particular coding paradigm. Many years ago, before I worked with X11, it is one that I would have been skeptical of beforehand. Fortunately, with experience, it has proven itself to me to be useful, and the Carbon way of using forward reference structures in the public header is a lot more type-safe over the X11 style of using typedef'd void*. > Thanks a lot for all your help. You're welcome. Sincerely, --Eljay