10

Related to a previous question, I can't understand some rules of MISRA C 2004.

In ISO C99 draft 2007, in 6.5 section §4 :

Some operators (the unary operator ~, and the binary operators <<, >>, &, ^, and |, collectively described as bitwise operators) are required to have operands that have integer type. These operators yield values that depend on the internal representations of integers, and have implementation-defined and undefined aspects for signed types.

Ok, using a signed integer with bitwise operators can produce undefined behaviour (and makes no sense).

A good solution is to use explicit conversion to a wider unsigned integer type in order to by-pass integral promotion, and then not use signed value with bitwise operators (see associated answers of my previous question).

But in MISRA C 2004, use of small unsigned integers with bitwise operators is possible (rule 10.5 for example). Why, if integral promotion leads to use signed values with bitwise operators? I think I don't understand some things.

Community
  • 1
  • 1
no_name
  • 295
  • 1
  • 2
  • 14
  • 1
    I'm not sure I understand the question, but it shouldn't matter if a an unsigned value is promoted to a larger type. Positive numbers and unsigned numbers less than the max signed value look the same, i.e. the sign bit is 0. – Caleb Oct 07 '14 at 15:09
  • unsigned integer types will not result in signed int due to the integral promotion. for example unsigned short will always become an unsigned int and never a signed int. – mch Oct 07 '14 at 15:14
  • 4
    @mch Not true on systems where short and int have different size. If an unsigned short can fit inside an `int`, it will get promoted to an `int`, which is signed. – Lundin Oct 07 '14 at 15:15
  • I don't see any unsigned requirement in the above section – phuclv Oct 26 '14 at 04:40
  • Sorry, I don't understand your comment. What do you mean ? Perhaps is a detail : if integral promotion provides an signed integer type, then use of bitwise operator have implementation-defined and undefined aspects. But in this case integral promotion provides always unsigned VALUE (but with signed integer TYPE) and then use of bitwise operators is not a problem. In this case, ISO C99 requirement must be "These operators yield values that depend on the internal representations of integers, and have implementation-defined and undefined aspects for signed VALUES.", no ? – no_name Oct 27 '14 at 07:12

1 Answers1

1

The rules don't contradict each other and you don't need to widen the type. You can immediately cast the result of small integer binary operation back to its type.

A small integer will not be promoted to int for shifts unless the first operand is int.

This is from their example:

uint8_t port = 0x5aU;
uint8_t result_8;
uint16_t result_16;

result_8 = (~port) >> 4;  /* not compliant */
result_8 = ((uint8_t)(~port)) >> 4; /* compliant */
result_16 = ((uint16_t)(~(uint16_t)port)) >> 4; /* compliant */
James
  • 6,978
  • 2
  • 17
  • 18
  • 4
    -1 this answer is not correct. See C11 6.5.7 `The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand.` – Lundin Oct 07 '14 at 15:21
  • I was referring to the result, which honors signedness: "The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2E2" – James Oct 07 '14 at 15:27
  • 2
    E1 and E2 refers to the operands after integer promotion. The text you cite refers to the poorly specified behavior which occurs when you shift things in and out of the sign bits of a negative number. – Lundin Oct 07 '14 at 15:30
  • @JamesRoth: I agree : ~port return a value with signed int type and right shift on signed int value can have undefined behaviors (this is the goal of 10.5 rule). But my question concern the type of operands *before* bits complement operation ("~"). In this case, conversion from uint8_t to signed int is performed (integral promotion) and then "~" bitwise operator applied on this type. Applying bit operators on signed int seems to be not a good idea or I don't understand ISO C99. – no_name Oct 07 '14 at 18:01
  • 2
    @JérômeBurlando The point is, if you apply ~ to a promoted variable which is now signed int, you'll get rubbish in the ms byte(s). If you immediately cast the variable back to uint8_t however, you'll discard the rubbish byte(s). – Lundin Oct 08 '14 at 06:20
  • @Lundin: Is a behavior specified in ISO C 99 ? Without a correct specification of behavior of bitwise operator on signed int, I can't justify this code. However, I agree with you forever, but in safety critical verification activities, I must rely this behavior to a standard. Especially since I have a warning of my static analysis tool. Cast to widening type solve problem for static analysis... I am just surprised that the MISRA not talking about this case. – no_name Oct 08 '14 at 06:38
  • @Lundin if the system is not 2's complement, then `(uint8_t)~port` is gives a different result to `(uint8_t)~(unsigned int)port` and the latter is probably what was intended. – M.M Oct 09 '14 at 22:15
  • @JérômeBurlando This behavior is the same in every C standard, and in C++ as well. There are various kind of undefined- and impl.defined behavior associated with the bitwise operators, depending on which operator you use and what you do with the result. Read chapter 6.10 of MISRA-C:2004, plenty of explanation there. – Lundin Oct 10 '14 at 06:14
  • @Lundin : In [link](http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf), section J.3.5, bitwise operations on signed int is specified have implementation-defined behavior. Perhaps not after integral promotion ? I can't find more informations in Standards... – no_name Oct 10 '14 at 09:43
  • @Lundin: MISRA C 2012, section 8.10, rule 10.1, Rationale item 6 says : "Shift and bitwise operations should only be performed on operands of essentially unsigned type. The numeric value resulting from their use on essentially signed types is implementation-defined.". Ok, but I don't understand why a behavior of operators with essentially operands is implementation-defined while C standard don't know "essential type" and here essential type is different (unsigned) as standard type (signed). My compiler is ISO C99 compliant, not MISRA compliant. – no_name Oct 10 '14 at 09:44