Object-oriented C is simple: Part 2

December 06, 2012

USA Firmware-December 06, 2012

If you're a C programmer who isn't yet proficient in C++, this doesn't mean you can't use simple object-oriented practices in C. This blog we discuss placing public variables.

Welcome back to our discussion on object-oriented C programming. This is the second installment in our series. In the first installment we discussed techniques to organize your files as if they were objects and that by following some basic rules, you can emulate private and public functions. So how about public and private variables?

Rule #3: Place private declarations of functions and variables in a separate file from those that are public to the module.

This solves the problem of variables getting into the wrong hands. We all know what happens when you let a variable run wild and free; Unmaintainable code. Ugly, complicated, and "You see that guy over there who blocked the entrance to his cube with a bunch of chairs, has a pile of broken keyboards under his desk with the big 'LEAVE ME ALONE' sign hanging on his partition? He knows how it works. Go see him" kind of code. Not pretty.

So where were we? Ah yes. Private variables.

Let's return to our motion sensor project. All our private variables will be placed in the file: MotionSensorPRIVATE.h

And as we saw last time, if you attempt to add this private include in a list of public includes, we will all know who to blame as it will yell from the mountain tops "Why am I here and what am I doing?" Or in the words of your esteemed colleagues "Dude! Why did you place my private header in your files header list!", or something like that.

What can you imagine would be included as private attributes of a motion sensor? How about something like this:

   unsigned int uiDetectThreshold;    //Programmable detection threshold. 
    unsigned int uiAdcMeasurementGain; //Programmable A/D gain.
    unsigned int uiDeltaCounts;        //ADC count change over fixed time.
Well this is fine, but we aren't taking advantage of the language. When these variables become part of expressions in MotionSensorPUBLIC.c, they should be represented as part of the MotionSensor "object" and not just variables of type unsigned int. How about this instead:

typedef struct
{
    unsigned int uiDetectThreshold;    //Programmable detection threshold.
    unsigned int uiAdcMeasurementGain; //Programmable A/D gain.
    unsigned int uiDeltaCounts;        //ADC count change over fixed time.
}MOTION_SENSOR_STRUCT;

static MOTION_SENSOR_STRUCT dMS;       //Sensor's private attributes
So now we have arrived at our next rule:

Rule #4: Place all your private variables inside the walls of a structure.

Clearly we are using the structure as a class that holds the private member variables. So should we, could we, include the private methods (functions) in this structure as well? Yes but I wouldn't. First of all, we've already solved the problem of isolating private and public functions by using two include files instead of one. Secondly this goes back to the "keep it simple stupid" KISS method of programming. If you go this route you will obfuscate your code (unless you're into that kind of thing--brouhaha!) and create unnecessary complexity sure to confuse the learning and the learned.

Complexity is a breeding ground for bugs. They love those warm and moist complex landscapes to burrow into where they won't be found for days, weeks, or possibly even months. So my answer is yes you can but no you shouldn't and no you don't need to. Enough said? Right? Right.

So how can we make this rule easily enforceable? Sure we could append or prepend something like _Private to every single blasted variable and you will end up with a sea of these appendages distracting you from the flow of the code.

There may be a good solution to this and I would love to hear your suggestions on the blog. Regardless, keeping all the attributes within a structure is certainly a good start.

So what about the public variables? To that I say, what public variables? That sounds a lot like a global variable to me. I would rather see you include everything inside the private structure and have getters and setters to access them as you would in C++. In fact I would make it a goal of yours to have no variables defined inside your public header. enum? Sure. But variables? No. In other words, "make them ask nicely" for your variables. Interestingly get and set isn't exactly nice is it? I mean it's downright demanding don't you think? Maybe we should throw in a please and thank you. But I digress, again.

Plenty more to come! We're not done yet! Perhaps I'll throw an RTOS into the mix next time. Stay tuned! and we'll see you in the trenches.

Robert Scaccia is a firmware consultant and president of USA Firmware, LLC. He is very active with a large network of firmware consultants throughout the United States and Canada, is chair of the IEEE Cleveland Computer Society, and founded the largest regional, as well as international, firmware group on LinkedIn. Email him at bob.scaccia@usafirmware.com, or visit www.firmwareplanet.com or www.usafirmware.com.

Loading comments...

Most Commented

Parts Search Datasheets.com

KNOWLEDGE CENTER