2

I'm at wits end. I can't get MISRA to stop complaining.

typedef unsigned char T_u8;
typedef signed char T_char;
T_u8 value = 0u;
T_char out[some_length];

Begin

out[size_out--] = (( value | 0x30) );
scm.c  320  Note 960: Violates MISRA 2004 Required Rule 12.7, Bitwise operator applied to signed underlying type: |
scm.c  320  Info 734: Loss of precision (assignment) (8 bits to 7 bits)

Sure. Makes sense. I will change it so I am OR'ing the same type.

out[size_out--] = (( value | 0x30u) );
scm.c  320  Info 713: Loss of precision (assignment) (unsigned int to char)

So, with the OR expression, the expression is being promoted to an unsigned int. So, I should cast it to the type it is expecting.

out[size_out--] = (T_char)(( value | 0x30u) );
scm.c  320  Note 960: Violates MISRA 2004 Required Rule 10.3, Prohibited cast of complex integer expression: Signed versus Unsigned

Now what? I don't get it. Why can't I cast it? What do I have to do?

out[size_out--] = (T_char)((T_u8)( (T_u8)value | (T_u8)0x30u) );
scm.c  320  Note 960: Violates MISRA 2004 Required Rule 10.3, Prohibited cast of complex integer expression: Signed versus Unsigned

This didn't help:

out[size_out--] = (( (T_u32)value | (T_u32)0x30) );
scm.c  320  Info 713: Loss of precision (assignment) (unsigned long to char)
user694733
  • 15,208
  • 2
  • 42
  • 68
  • 1
    You might want to mention which static analyser you are using. It is not "MISRA" that is complaining, it is your tool. – Lundin Jan 31 '18 at 07:45
  • I'm not really sure which static analyzer I am using. It's not mine. But, your absolutely right. I thought it was MISRA that was complaining. – Christopher J. Holland Jan 31 '18 at 17:56
  • How can you not know which tool you are using? Are you not the programmer? – Lundin Feb 01 '18 at 07:51
  • I did not setup the environment. It is a work environment. The tools are outdated, MISRA rules were never followed, Yes. I am the programmer, not the tools person. Why it wont compile with an 'Info' complaint, doesn't make sense, but it does. Hence the reason I thought I was a MISRA problem. – Christopher J. Holland Feb 02 '18 at 12:43

1 Answers1

2

The first problem is that you made the literal unsigned, which is indeed required. This however made the expression value | 0x30u an implicit conversion to a different "underlying type" (MISRA-C:2004-only term) of different signedness. Rule 10.1.

You can fix this by forcing an explicit conversion before the | operator is applied:

out[size_out] = (unsigned int)value | 0x30u;
size_out--;

Please note that mixing ++ or -- with other operators in the same expression violates another MISRA rule, for very good reasons, as doing so is dangerous practice.


The above should be enough to sate MISRA-C:2004, though there is still an implicit conversion (lvalue conversion) back to char type. This doesn't violate MISRA but your tool might apparently whine about it still. This is not a MISRA warning:

"Info 713: Loss of precision (assignment) (unsigned long to char)"

It is a rather pedantic warning, though you could add an additional cast to make it go away:

out[size_out] = (T_char)((unsigned int)value | 0x30u);

One of the main purposes of MISRA is to enlighten programmers about how implicit type promotions work in C. They are one of the biggest flaws of the language, and until you study how they work (they are not exactly trivial), you can probably forget about writing MISRA-compliant code. Or bug-free code for that matter. I've tried to explain how the most common ones work here: Implicit type promotion rules.

I would also advise you to upgrade to MISRA-C:2012. It is a more rational document that fixed many problems of MISRA-C:2004. For example, the concept of "underlying type" was replaced.

And finally, you really should start using stdint.h instead of using your own non-standard typedefs.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    How is `(unsigned int)value` different from the standard promotion of `unsigned char` in a binary operation with unsigned literal `0x30u`? You summarize in the linked question/answer as, "if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank". – Toby Speight Jan 31 '18 at 09:16
  • @TobySpeight The difference is that with an explicit cast, you _document_ your code and prove that "I know what I'm doing, I have actually considered integer promotions/usual arithmetic conversions". Code lacking the cast says "Either I considered promotions, or alternatively I have no clue what I'm doing and my code will therefore potentially be full of bugs." Where the latter scenario is, sadly, far more likely. Notably, without the `u` suffix on the literal, the operation would be carried out on an `int`, which could potentially introduce undefined behavior. – Lundin Jan 31 '18 at 12:39
  • Thank you, but no matter what I seem to do, I still get the error "Violates MISRA 2004 Required Rule 10.3, Prohibited cast of complex integer expression: Signed versus Unsigned" It's not letting me cast from an unsigned long to a signed character type. I tried casting to an unsigned character type, then to an unsigned character type. That doesn't work either. I also tried promoting both values to unsigned longs. Maybe it is the MISRA-C:2004 I will have to upgrade and see if something changes. P.S. Int is vague. Is it 8,6,24,32,64 bits? Hence T_u32, T_u16, etc. – Christopher J. Holland Jan 31 '18 at 18:20
  • Rule 10.3 means that you aren't allowed to do `(unsigned int)(value | 0x30u)`, because confused newbies think such casts mean that the operation is then carried out at the casted-to type. `(value | 0x30u)` is MISRA's definition of a "complex expression". But in my answer, I do not cast the _result_ of the complex expression - the cast happens before that. It is perfectly fine and MISRA-C:2004 rule 10.3 compliant. The problem is that your static analyser is broken. Regarding your PS, that's indeed why you should use `stdint.h` like I said, and not your own "garage hacker" types. – Lundin Feb 01 '18 at 07:54
  • Rule 6.3 (advisory): typedefs that indicate size and signedness should be used in place of the basic numerical types. scm.c 307 Note 970: Use of modifier or type 'signed' outside of a typedef [MISRA 2004 Rule 6.3] scm.c 307 Note 970: Use of modifier or type 'char' outside of a typedef [MISRA 2004 Rule 6.3] – Christopher J. Holland Feb 02 '18 at 13:23
  • I finally got it to work! I used an intermediate value. T_u32 val2 = ((T_u32)value | (T_u32)0x30u); Then cast that value to the signed char. out[size_out--] = (T_s8)val2; Why it would not work in one expression? I have no idea. All I know is that it works now. – Christopher J. Holland Feb 02 '18 at 13:40
  • @ChristopherJ.Holland It works in a single expression just fine, as per my answer. To double-check I just now verified the code in the answer with my old MISRA-C:2004 checker, LDRA Testbed. No warnings, no MISRA violations. As a side note the same code also passes MISRA-C:2012 checks. – Lundin Feb 02 '18 at 13:47