2

I'm getting errors from our static analysis tool about the following snippet:

uint8_t value = 24U;
char buffer[512];
int chars_printed = snprintf(buffer, sizeof(buffer),
                             "The value in hex is 0x%02hhX\r\n",
                             value);

The error is:

MISRA-2004 Rule 10.1 violation: implicitly converting a non-constant expression in a function argument. Converting "value", with underlying type "unsigned char" (8 bits, unsigned), to type "int" (32 bits, signed).

What is the signedness and bit-width that MISRA is expecting from a "%X" specifier?

The "%X" is said to take an unsigned int from the cppreference page.

There are no errors from the IAR Compiler's MISRA C 2004 checker.
This one is from Coverity.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • 1
    `snprintf` takes a variadic argument list, so `value` will undergo integral promotion. You should be able to silence the warning by casting `(unsigned)value` – Praetorian Apr 28 '15 at 00:08
  • @Praetorian, that doesn't explain the signedness issue. I'm fine with the same signedness promotion to a larger type, but where is this "int32_t" type coming from? Is it the variadic argument list? I don't see any parameter definitions in any of my C language resources. – Thomas Matthews Apr 28 '15 at 00:19
  • 2
    If you pass a type smaller than `int` in a variadic argument list it gets promoted to `int`. Read the *default conversions* section [here](http://en.cppreference.com/w/cpp/language/variadic_arguments). – Praetorian Apr 28 '15 at 00:26
  • Do you have a link to that source, pdf? – 2501 Apr 28 '15 at 02:06
  • http://stackoverflow.com/q/1255775/995714 types narrower than int will be promoted to int – phuclv Apr 28 '15 at 03:28
  • Variadic arguments invoke the _default argument promotions_, that in turn invoke the _integer promotions_, which the MISRA rule is concerned about. Though variadic argument functions as well as stdio.h are both banned by MISRA-C anyhow. – Lundin Apr 28 '15 at 11:05

1 Answers1

5

The problem is that the printf family implicitly promotes all arguments of a small integer type to int. Implicit type promotions of that kind is not allowed by rule 10.1 and this is why you get a MISRA violation error. It has nothing to do with the format specifier.

For MISRA-compliance, simply cast the value explicitly before passing it to the function: (uint32_t)value.

Please also note that MISRA doesn't allowed you to use stdio.h in production code.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • So as a sidenote, Coverity seems to do a better job than IAR in this case. – Lundin Apr 28 '15 at 11:01
  • Actually, MISRA does allow usage, as long as the variance is documented. We are using the string printf and scanf functions; since we don't want to write and test our own. – Thomas Matthews Apr 28 '15 at 16:35
  • 1
    @ThomasMatthews Documenting all the poorly-specified behavior and all other pitfalls that come with the stdio.h functions seems like quite a monumental task... you'd have to write a book. It is a good rule, using these functions in production code for a mission-critical system is very questionable practice. As for sprintf/sscanf, rolling out your own version of them is less than one hour of work given that you only use them to convert to/from integers (and not floats etc). – Lundin Apr 28 '15 at 16:51