1

I am using PCLint v 9.00h

In my code I have the following (where S16 is a signed 16 bit):

S16 temperatureResult = -32768;

Which unless my brain has stopped working is the smallest value that can fit into this type

But I am getting a lint error of "Violates MISRA 2004 Required Rule 10.1, Implicit conversion of integer to smaller type"

If I change the value to -32767 it works fine.

Am I missing something obvious?

Firedragon
  • 3,685
  • 3
  • 35
  • 75
  • Correct me if I'm wrong but Doens't the c99 TC3 say that it is implementation defined about they may serve a + and - value of 0? So if thats the case you would have 1 less negative decimal value. – dhein Oct 15 '14 at 06:13
  • What is the reason to use a non-standard type for that? If your compiler is C99 you should have `int16_t` and `INT16_MIN` that would work out of the box. – Jens Gustedt Oct 15 '14 at 07:22
  • @JensGustedt It's a coding standard requirement led by MISRA requirements which hasn't been updated for a while. Don't know if the compiler is C99 – Firedragon Oct 15 '14 at 07:28
  • That MISRA rule is quite strange. Gcc (and probably many other compilers) can warn about non-value preserving conversions of constant expressions. The cast hides possible bugs; if the value is changed to, say -32769, where the compiler warning probably would be helpful. – mafso Oct 15 '14 at 11:46

4 Answers4

4

It doesn't necessarily "not fit". Quite possibly it fits. (Did you actually check it?)

  • If your platform uses 32-bit (or larger) int, then all arithmetic expressions are evaluated in 32-bit int type and the warning simply tells you that you are converting an int value to a smaller type. PCLint simply didn't bother to check whether the actual value fits into the destination type.

    You might be able to suppress this warning with an explicit type cast

    S16 temperatureResult = (S16) -32768;
    
  • If your platform uses 16-bit int, then a slightly different issue might be involved here. In C language -32768 is not an atomic constant. -32768 is actually an expression consisting of an unary - operator applied to a positive constant 32768. 32768 is a positive constant that does not fit into a 16-bit type, for which reason the compiler uses a larger type (32-bit long int probably) to represent 32768. Consequently, -32768 is evaluated in the domain of a larger type and also ends up as a value of larger type. PCLind decided to warn you about the implicit switch to a larger type. (See (-2147483648> 0) returns true in C++? for more details.)

    If that's what's happening here, then to avoid the warning you can use an explicit type cast

    S16 temperatureResult = (S16) -32768;
    

    or, alternatively, you can express the initialization as

    S16 temperatureResult = -32767 - 1;
    

    In the latter case the compiler should be able to evaluate the constant expression within the domain of 16-bit int type.

Community
  • 1
  • 1
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • In C all integral literals are of type int or larger, and all integral expressions are of type int or larger. Nothing ever is evaluated as short. – n. m. could be an AI Oct 15 '14 at 06:35
  • @n.m.: That is true. (My answer is misleading in that regard. Indeed, if the larger type was used, it wouldn't be `int`. I removed explicit references to `int` from the answer.) However, could it be that the platform actually uses 16-bit `int`? 16-bit `int` is allowed by the language. In that case the issue is that an even larger type was used to evaluate the expression. Unfortunately, the warning message does not mention the exact types. – AnT stands with Russia Oct 15 '14 at 06:42
  • +1 good description what is going. But for the solution, any decent compiler should have macros for such constants, `INT_MIN` if this is just the `int` type, or `INT16_MIN`. – Jens Gustedt Oct 15 '14 at 07:21
3

The standard only guarantees the range of [-32767,32767] for signed short. Your implementation may extend this a bit, like most implementations do, but PCLint checks for standards compliance.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
3

First of all: it doesn't have to deal with -32768 by standard:

5.2.4.2.1 Sizes of integer types

[...]

— minimum value for an object of type short int

SHRT_MIN -32767 // -(215 - 1)

— maximum value for an object of type short int

SHRT_MAX +32767 // 215 - 1

(I'm looking for the part which makes a enviroment defined note about supporting -32768 anyway)

Got it:

The reason why there is sometimes anyway one more number supported is justified by this paragraph:

6.2.6.2 Integer types

[...]

2 — For signed integer types, the bits of the object representation shall be divided into three groups: value bits, padding bits, and the sign bit. There need not be any padding bits; there shall be exactly one sign bit. Each bit that is a value bit shall have the same value as the same bit in the object representation of the corresponding unsigned type (if there are M value bits in the signed type and N in the unsigned type, then M <= N). If the sign bit is zero, it shall not affect the resulting value. If the sign bit is one, the value shall be modified in one of the following ways:

— the corresponding value with sign bit 0 is negated (sign and magnitude);

— the sign bit has the value -(2N) (two’s complement);

— the sign bit has the value -(2N - 1) (ones’ complement).

Which of these applies is implementation-defined, as is whether the value with sign bit 1 and all value bits zero (for the first two), or with sign bit and all value bits 1 (for ones’ complement), is a trap representation or a normal value. In the case of sign and magnitude and ones’ complement, if this representation is a normal value it is called a negative zero.

(All I'm quoting is written in ISO/IEC 9899:TC3)

dhein
  • 6,431
  • 4
  • 42
  • 74
1

It comes to mind to try:

S16 temperatureResult = (S16) 0x8000; // ASSUMES twos complement integers

The explicit cast is because Rule 10.1 says

"The value of an expression of integer type shall not be implicitly converted to a different underlying type if ..."

Make it portable:

S16 temperatureResult = -32767 - 1;

But anyway, if MISRA requires compatibility with ones complement computers (like some Cray supercomputers), then the guaranteed range of signed 16-bit is only [-32767 ... 32767] so you can't achieve what you're trying to do.

Jerry101
  • 12,157
  • 5
  • 44
  • 63
  • Same error and an additional one (Loss of information (initialization) (16 bits to 15 bits)) – Firedragon Oct 15 '14 at 06:09
  • @Firedragon if MISRA requires compatibility with ones complement computers, then the guaranteed range of signed 16-bit is only to be [-32767 ... 32767]. – Jerry101 Oct 15 '14 at 06:14
  • Thanks for the information. It sounds like ones complement then which I didn't know about so have learnt something new today – Firedragon Oct 15 '14 at 06:16
  • This causes implementation-defined behaviour. Whether or not it agrees with MISRA, it's probably something you should avoid given that there is a more portable version. – M.M Oct 15 '14 at 06:31
  • @MattMcNabb agreed. It's so hard to write portable code in C. Anyway if the code has to be portable to ones complement computers, then the answer is "no can do." – Jerry101 Oct 15 '14 at 06:39
  • @Firedragon there is also sign-magnitude format, not only one and two's complement. And C allows all 3 formats for signed type http://stackoverflow.com/questions/3952123/representation-of-negative-numbers-in-c – phuclv Oct 15 '14 at 07:33