-1

The facts

This is a very similar question to this one, but here I am talking about a more general case the MISRA-C3 Rule 5.0.2 or the SEI CERT C EXP00-C rule (more permissive).

Within MISRA-C3 I shall use parentheses to avoid implicit operator precedence. So the following code is correct, but to my eyes very boilerplate:

 if ((((x * y) + 3) > z) && ((w - 1) <= (42 + (x / (y + z)))))

Note: as I was writing this expression I had to copy/paste it in my code editor to fix the missing parenthesis because it got too cumbersome.

As an experienced programmer I would only use parenthesis for non-obvious precedence that may depend on the programming language I use. The C Operator Precedence Table may not be easy to learn, especially for new C programmers and sometime even for my self when I am tired by hours of programming in the middle of the night.

My rule of thumb is:

Parenthesis shall be used for explicit operator precedence with all operators except the logical and (&&) and or (||), and the 4 basic operations (* / + -).

The above expression can therefore be simplified like this:

 if ((x * y + 3) > z && (w - 1) <= (42 + x / (y + z)))

The latter expression looks much easier to read and I can see at a glance if I am missing a parenthesis.

Moreover, as the equal (=) operator also falls under the MISRA rule. Developers should also write z = (a * b) and not z = a * b.

The story behind

I am working in a company where the developers are far from experienced in C programming despite they all do C programming for more than 10-15 years. They keep adding useless comments x = 2; // Assign x with 2 everywhere and claims the first expression I wrote is much more readable because no human can learn by heart the operator precedence. So they usually use comments, parenthesis or forward declaration everywhere rather than using their common sense to keep the reading flow clear and understandable.

I was trying to teach them the beauty of programming where the programmer has to tell a story and keep the flow crystal clear by avoiding useless things they put everywhere because once someone told them to do so.

Today I am questioning myself and wondering if I am right or wrong about this parenthesis thing. Perhaps the first expression is more understandable than the second one for most people.

Examples

if ((i > LENGTH) && (((a * b) + c) > (d + e)))  // Bad
if (i > LENGTH && a * b + c > d + e)  // Good

y = ((x * y) + 1);  // Bad
y = x * y + 1;  // Good

The question

Is my rule of thumb (yellow box above) a good rule? The MISRA C3 Rule 5.0.2 is only advisory and CERT-C is more into my direction.

  • 1
    What makes you say that your team is "far from experienced in C programming" if "they all do C programming for more than 10-15 years"? – Tersosauros Mar 4 '18 at 14:33
  • 1
    Well, when some of your colleagues ask you what ‘extern’ does or “Can we include a header located in a sub-directory?”, “What is ‘size_t’?” or even “What is the comma operator you are talking about?”, I tend to consider they are not experienced... I am perhaps picky but I think a good C developer should have read the C99 standard and should know that ‘switch’ are usually compiled using a jump table... – nowox Mar 4 '18 at 14:50
  • I have tried to have this discussion before. I lean towards using the language as designed, relying on future maintainers to: 1) know the language 2) not be in a hurry, and 3) have basic understanding of the intent of code they are editing. Basically, do all I can to make things more readable, with variable names, whitespace including line breaks and so on, without being obsequious. If one of my three conditions is not met, then what exactly am I to do about that? It is not my problem. There is no internal brake light to give you feedback that you pushed the brake pedal, you just have to know. – user251748 Mar 22 '18 at 14:55
  • 1
    MISRA is for safety-critical applications and therefore very strict. If these rules fit your project is something you have to decide yourself. – Simon Mar 22 '18 at 18:04
  • 1
    @Andrew it is an interesting question. Oodles of people are able to drive a car pretty successfully, when it is actually a very dangerous activity requiring concentration, reflexes and experience. Overall it works out. I think it works because it is based on our ability to walk, which has been honed by evolution. Programming is quite different, and because of the danger of affecting many many people with mistakes, I suggest taking only excellent programmers, and having them back each other up, like flying the Space Shuttle or something: it is not for everyone. – user251748 Apr 9 '18 at 14:45
10

If you need to follow some standard, then follow that standard even if the advice seems suboptimal. Note that many coding standards and guidelines have a specific goal in mind. MISRA is geared towards security, and therefore wants to eliminate any possibly confusing constructs. As operator precedence can sometimes be confused even by experienced programmers, explicitly parenthesizing your expressions is in line with that goal.

For coding conventions within your organization, the goal probably isn't elegant, beautiful code, but maintainability by all programmers. Your coding conventions should be oriented around the lower end of the skill distribution in your team. This is basically the same issue as the recent Is it OK to use meta-programming? question. So don't do what's pretty in your eyes, do what is understood by all team members.

Note that all your code snippets are a red herring. I would flag most of your examples in a code review. Not because they do or don't use parentheses, but because these expressions are terribly complex. The whole parenthesisation issue is far less urgent if you extract sub-expressions as separate variables. As an added benefit, these variable names can make the code more self-documenting. Even if no one else does this, you can use such techniques to improve code that you write.

  • 1
    I perfectly agree with you with the code-review part. I would also flag my own examples. – nowox Mar 4 '18 at 12:23
  • 2
    @nowox Going for 80% would defeat the purpose of any standard because you would be back at "totally arbitrary" again. You either adopt one or live with the fruitless conflict in your team about any aspect of code formatting. It reads like there is just not enough support for your preferred way in your team. Whether anyone here agrees with you hardly matters. – Martin Maat Mar 4 '18 at 12:39
  • 3
    @nowox If you have the political capital to write and implement a coding standard that is great. It's generally sensible to leave common-sense rules at the discretion of the programmer, and only write down actual decisions that the team made. A coding standard is 100× more valuable if it can be checked automatically as part of your test suite, as that avoids later squabbles about irrelevant details. – amon Mar 4 '18 at 12:41
  • 1
    @MartinMaat I do not agree with this point. I think with MISRA-C3 most of the rules are very good for every types of C program, but some only apply to embedded applications. For example you cannot use stdio.h with MISRA-C3, so based on your opinion, we either need to follow 100% MISRA or not to use it and throw away what is good for everyone. I think the best is to understand our needs, make the best compromise between readability and safety and define a company standard that list the good rules of MISRA to use for all type of C development. – nowox Mar 4 '18 at 13:07
  • 1
    @nowox then fine, do that. But that's up to you and the other developers in your company to agree. Which "the good rules" are, as you've already noted with your example of embedded applications, is going to depend on the context. For what it's worth I don't like either of your "good" or "bad" examples, but it's up to a team/company to define their standards. – jonrsharpe Mar 4 '18 at 14:17
5

Well, I would write your example almost exactly as you stated is the "bad way", because I'm not writing it for me, I'm writing it for the next engineer(s), and they may not have the understanding of the functionality down as much as I do.

Let's take the second (simple) example in your last code block:

y = ((x * y) + 1);  // Some valuable comment here or maybe no comment at all

This makes the future person reading the code (and possibly changing it) understand that I'm setting y to the increment of the product, versus the product of the increment. To me, when I've read code written by someone years ago and I'm looking for an understanding of what's going on, this version makes me quickly see that the product is incremented.

y = x * y + 1;  // Possibly some useless comment

My initial quick, barely-a-glance reading (because I'm pressed for time, have no good understanding of the code, and really want to get back to YouTube development) might not get that the product is incremented, especially if the comment is a little vague. Now I have to stop my barely-a-glance reading and think about:

  1. What they wanted to do
  2. What they really did
  3. What might happen if they didn't do what they wanted

Explicit parentheses? I personally love them when I'm writing and I love them when I'm reading. One thing I do do is to use temporary variables and white-space to my benefit so that it's easier to read.

Taking the first example:

if ((((x * y) + 3) > z) && ((w - 1) <= (42 + (x / (y + z)))))

I would write as (if I didn't want to use temp variables):

if (   (((xDim * yDim) + PROD_OFFSET) > zVolume)
    && ((wDim - EDGE_FACTOR) <= (MAX_THRESH + (xDim  / (yDim + zVolume)))))
{
...
}

Now it's easier for me to see that there are two (2) conditionals that must be met (now each on their own line) and my variables and constants now make a bit more sense. (I know the variable and constant names were random for your example, but I wanted to show a complete comparison.)

Parenthesis/brace matching? Good IDEs (with integrated LINT) always let you know ahead of time.

  • 2
    +1 for splitting complex conditionals onto multiple lines. – user949300 Mar 22 '18 at 0:54
  • +1 for thinking about they who come afterwards – Andrew Apr 9 '18 at 11:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.