(Reading time: 5 – 8 minutes)
>>>NOTE: You may want to start with a much simpler article in hiding member in structs.
Data hiding and encapsulation in C is fairly easy using the notions of derived and incomplete types. A derived type is a user-defined type typically declared as members of a struct. An incomplete type is where the definition of a type is located within the scope as the type declaration. Incomplete types extremely useful for data hiding when type declaration is in the header file, and the definition and implementation of the type is shrouded in the C source file. For example, consider defining a type for handling paintings in an art collection:
1 2 3 4 5 6 | struct painting { uint32_t inventory_control; uint32_t purchase_price; char painting_name[256]; char artist_name[256]; }; |
This struct definition could be placed in a header file, say, painting.h, for inclusion into application code, then the members of the struct can be accessed as needed. But what happens when you need to change the members of the struct? Perhaps you would prefer to allocate the char buffers instead of declaring their sizes statically, and need to add a member for current owner:
1 2 3 4 5 6 7 | struct painting { uint32_t inventory_control; uint32_t purchase_price; char * painting_name; char * artist_name; char * owner_name; }; |
Now all the code depending on the first definition is broken. One way out of this bind is using incomplete types with accessor methods, just as you would use them in Java or C++.
In the header file painting.h, declare the painting type with a typedef:
typedef struct _painting Painting;
How you choose to capitalize, underscore or otherwise name “classes” is your business. Personally, I loathe the so-called “CamelCase” convention, but will use capital letters to denote a user-defined type.
Memory management
Managing memory is one of the most error-prone aspects of writing code in the C programming language. Using incomplete types, notice that you now have no way to directly allocate memory for your type in your application program, although you can deallocate using free() anywhere you have a Painting pointer declared. So allocation must be wrapped, and it makes really good sense to wrap the deallocation as well. For example, here is how I do it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | Painting * painting_new(void) { Painting * p = (Painting *)malloc(sizeof(Painting)); memset(p,0xda,sizeof(Painting)); return p; } void painting_delete(Painting * p) { free(p->artist_name); free(p->owner_name); free(p->painting_name); memset(p,0xdd,sizeof(Painting)); free(p); } |
So what’s going on here? Why the call to memset? And why different values when allocating (0xda) versus freeing (0xdd)? This technique is called “shredding” and I was first exposed to it in an excellent
book by Steve Maguire called “Writing Solid Code.”
The purpose of shredding is to set all the bytes in a struct (or other allocated set of bytes to a value that has meaning to the programmer, but is otherwise nonexecutable nonsense. The value of this practice is suddenly realized when stepping through code in a debugger. Series of 0xdadadada indicate you are accessing an uninitialed field in the data structure. Similarly, series of 0xdddddddd indicate you are accessing memory that has been freed.
Defining accessors
Now, in the c file, define the _painting struct as above, and provide get/set methods for each member. For example, to get and set the values for artist_name, I write these methods as follows:
1 2 3 4 5 6 7 8 9 | char * painting_get_artist_name(Painting * p) { return p->artist_name; } void painting_set_artist_name(Painting * p, char * artist_name, size_t s) { strncpy(p->artist_name,artist_name,s); } |
The appropriate prototypes for these methods are declred in the painting.h header file.
Again, how you choose to capitalize, underscore names and otherwise format your code is your business, but let’s take a closer look at my convention. First, I use the name of the struct (painting) to prefix all method calls that are publicly declared in the header file. I follow this with a verb (set or get) to indicate the action I want to perform, then the name of the member of the struct as object to the action, in this case “artist_name.” Note that I pass the length of the name in as a parameter for use in the strncpy function to guard against buffer overflow problems. (Where you get this length is your business as well).
Now, you have a header file that functions as an interface to your source code. You can add or delete members of any struct at any time without breaking your application code. To handle members that have been removed, you can signal error conditions in the appropriate get/set methods. Handling error conditions can be done in several ways, but that topic is outside the scope of this document at the moment.
Generate code automatically
Lastly, while all this code appears wordy, note that it’s pretty easy to write a code generator in any language that can handle regular expressions. I have written code generators in sh, perl and lua, which have variously taken key, value pairs or struct definitions as inputs. Developing an API with more than a dozen types of structs, each of which have 4 to 40 members makes automatic code generation time-effective.
Pitfalls
The approach above has some traps for the unwary, the most important of which is where and how to allocate memory for pointer fields in the struct. Several different approaches can be taken; I will investigate a couple in a future update to this post.
Links and resources
- Very good article on incomplete types in general.
- Incomplete types as data abstractions.
- Steve deKorte’s overview on Object-oriented C programming. (This link is currently broken. It was a good essay, and Steve deKorte is a very good programmer.)
Moving to C++
In c++, this technique is often referred to as “D Pointers,” “Handles” or “Opaque Pointers.” Some good links include:
Similar Posts:
- How To Hide A Struct Member in the C Programming Language
- C/C++ Naming conventions (Part II)
- Linking in Microsoft Visual Studio C++
Related Posts -
Developing WordPress Plugins on Windows using WAMP, Cygwin and Aptana Studio Developing WordPress plugins is not very difficult, in theory. PHP is not a difficult programming language, WordPress is well-designed with appropriate hooks for use by plugins, and there is extensive documentation. In practice, it can be a different story. [toc title="Table of Contents" hint="Click to expand/collapse" class="toc-right" style="width: 50%"] There's...... - Filing WithOut Reading: Subscribe to everything, FWORing for later search and perusal For many popular search terms, search engines suck, and suck badly. For example, I just did a search on Google for a pinyin translation of money. Now, I'm Old Skool, and think pinyin is for p^Hwussies. Real Men use Yale system... ...but never mind that. The point is that I......
-
Ignoring "~," ".bak" and Other Files in Subversion Do you ever spend a vast amount of time searching the web for how to do something that you know ought to be trivial, something you know takes 30 seconds to do, and will save you a huge amount of time, if only you could find out how to make...... - Curious WordPress Crash: Evidence of Black Hat SEO hacking... or simple incompetence? The Upshot... Fixing Call to undefined function wp() wp() will fail when wp-config.php file has Microsoft Windows line endings and is served by an Apache server on a Linux host. Changing the line endings from rn to n is easy: run wp-config.php through dos2unix. Errors in unix/linux executable files edited on......
-
Restoring Keymaster Access on bbPress --- Fixing one thing breaks another! [Update] March 20, 2009: bbPress Keymaster is chosen on install. When integrating with WordPress as here, this is the ID that's critical to preserve. Will update article as necessary. What a great day! Just kicking back on the couch, listening to some Morphine, laptop in the lap, upgrading security......
Related Websites - How Can I Make Money With Articles Using Banner Advertisements? Once the darling of the internet marketing world, and how almost all advertisements are done. Banner advertisements have been ignored by many internet marketers. However, if you have a content-rich, article based website it is very important to promote your site well and drive quality traffic to the site. One...
- iPhone Application Developer: making it easier to create and develop iphone applications The buzz of the town is smart and hi-tech iphone and what makes it so different from numerous other gadgets is its long list of never ending applications. The numerous iphone applications allow its user to surf the internet, email, play games, multimedia and so on and no wonder,......
- Windows Mobile application development Mobile and compact devices become more and more popular in our society. Each of us faces with them every day. Certainly each of us has mobile phone, hand-held computers or other hi-tech devices. All of these devices have different mobile platforms. There are such known platforms as Windows MobileM, iPhone,......






{ 1 trackback }
{ 1 comment… read it below or add one }
http://www.archive.org == “Internet Archive Wayback Machine”, i.e. a site that archives old versions of web pages.
Therefore the essay can be found in a few seconds, if you have the original URL (and you did):
http://web.archive.org/web/20070630120840/http://www.dekorte.com/docs/essays/ooc/