3 Explicit Programming Tips C Developers Should Follow

You know what they say when you ASSUME, you make an ASS out of U and ME. That’s exactly what developers are doing when they implicitly write their code and ASSUME that other developers can read minds across space and time. Embedded systems developers should be as Explicit as possible in order to avoid ASSUME syndrome and create unexpected behaviors in their systems. In today’s post, let’s examine several areas where developers can clean up their code by being more explicit.

Explicit Programming Tip #1 – Use extern with public functions

We all know that we shouldn’t be using extern because it creates global variables which in turn leads potentially to all sorts of problems. However, a great place to actually use extern is when you are creating a public function.

When you define a function that will be public, you can create the declaration or prototype in the header using:

void Foo(void);

It’s in the header so of course it is obvious that it’s a public, extern, function. However, I’ve come across cases where you’re maintaining a module someone else wrote and there is no public API in the header for a function like Bar but it is defined like:

void Bar(void)

{

}

What is the intent of this function? Is it supposed to be private and have a static thrown in front of it? Was it supposed to be public and be defined in the header?

There is no way to know what the original programmers intent was. Had the programmer defined Bar as:

extern Bar(void)

{

}

We would know that yes, it is public and is missing from the API, although the linker would still be able to find it if someone called it. (Yes, it would create a warning, but oh so many programmers still ignore these!).

 

Explicit Programming Tip #2 – Pass pointers as const to functions unless they change 

Pointers are dangerous and if they are accidentally incremented, decremented or modified in some unexpected manner during execution they can easily lead to disaster. I will often come across function declarations that look something like the following:

void Foo(uint32_t * Param1);

This declaration is so implicit that it drives me crazy! I read this declaration that the intent is to pass a pointer to a uint32_t where both the pointer and the uint32_t memory location being pointed to are allowed to change!

Is that the intent of the programmer? What if they just want to pass a pointer to a variable so that it is passed by reference and can be modified by the function? This function will do that, but they have also left open the option to modify the pointer too! (undoubtedly someone maintaining the code will get lazy and do it and then there is a fun bug waiting to happen!).

Again, we have to be explicit. The statement below is very clear to me that the pointer does not change and that the value being pointed to can change:

void Foo(uint32_t * const Param1);

This says the parameter is a const pointer to a uint32_t memory location. The pointer can’t change in the function, but the thing pointed to can. So, in the function if someone does a:

Param++;

The compiler will say “Nope! Error!”, making it obvious to the maintainer that they were not supposed to do that.

 

Explicit Programming Tip #3 – Pass “no reference” variables as const

Now this is the one that normally gets developers all excited, and not in a good way. I’ve been told this one is non-sense, but again, it makes the code crystal clear to any developer including newbies.

The idea here is that I may have a function declared like:

void Foo(uint32_t Param1);

In this case I’m passing in parameter by copy, not by reference, to be used by a function. The function can theoretically do whatever it wants with the local copy. We really don’t care, but again, if someone is maintaining this code, do they know that we want to receive the parameter and use it as a constant? To me, I would have no clue unless the statement was written:

void Foo(const uint32_t Param1);

This tells me that the parameter is not expected to change or be modified in the copy for local use.

It’s a small thing, which probably won’t result in some catastrophic failure, but where’s the workmanship and pride in writing clean and clear code?

 

Conclusions

These are a few tips that help make code a little bit clearer and will help a developer understand the true intent of the code. This is important because so much code today is left with giant gaping ASSUMPTIONS that lead to countless man years being lost every year. Now, these may not be the best examples for the implicit code that results in all that loss, but they do give you the idea that you should be writing your software to be as clear as possible. Software always seems obvious when you write it, but it rarely is obvious to someone else or to the future you who comes back and wonders: “Why was past me such an idiot?”.

6 thoughts on “3 Explicit Programming Tips C Developers Should Follow”

  1. #2, void Foo(uint32_t * Param1);
    Wouldn’t the point itself be a local copy? You could change it in the function but would not affect anything outside the function. Correct? I’ve seen plenty of this
    void Foo(uint32_t * Param1, int size)
    {
    uint32_t sum = 0;
    for (int i = 0; i < size; i++) sum += *Param1++;
    }
    Not the best practice, but not wrong either.

  2. If the compiler supports, best practice is to use C++ already 🙂 Use const reference
    template
    Type sum( const std::array& data ) {
    Type result = 0;
    for( const auto& el : data)
    result += el;
    return result;
    }

  3. #1 is interesting; I never thought of doing that and typically use different naming to indicate a function is intended to be public (e.g., MOD_ProcessData() vs. ModCheckInternalState()).

    Is the return type “void” missing from the example? That is, should it be:

    extern void Bar(void)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.