Bug 36588 - Request warnings about the precedence of the unary - over the binary * and /
Summary: Request warnings about the precedence of the unary - over the binary * and /
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.3.1
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2008-06-21 10:48 UTC by Vincent Lefèvre
Modified: 2021-09-13 00:08 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vincent Lefèvre 2008-06-21 10:48:20 UTC
The problem: it is too easy to write incorrect code with the unary "-", e.g.
  "- i / 2" (which means "(- i) / 2")
when one really wants "- (i / 2)". The reasons are:

1. Whereas the binary "-" has a lower precedence than the binary "*" (multiply) and "/" (divide), the unary "-" has a higher precedence. It is easy to forget this difference, in particular because the same symbol is used with two different precedences. For instance, the expressions "0 - i / 2" and "- i / 2" look the same, but the former corresponds to "0 - (i / 2)" and the latter corresponds to "(- i) / 2".

2. Mathematically (in a ring), the precedence of the unary "-" (for the opposite) vs "*" (multiply) does not matter since the result does not depend on the precedence, so that it is never explicited in practice and what the writer of a math expression really thinks depends on the context.

The following code shows such a problem that can occur in practice: the unary "-" in "k = - i / 2" yields an integer overflow, hence undefined behavior. The user may not be aware of it. And the fact that this bug is hidden with -O2 optimizations makes it worse. For instance, when compiling this code without optimizations, I get:
  j = 1073741824
  k = -1073741824
(which is not the intended result). With -O2 optimizations, I get:
  j = 1073741824
  k = 1073741824

Adding the following warnings could avoid bugs like this one:
  warning: suggest parentheses around unary - in operand of *
  warning: suggest parentheses around unary - in operand of /

Note: such warnings should also apply to floating-point expressions as they can be affected in the rounding directions FE_DOWNWARD and FE_UPWARD.

#include <stdio.h>
#include <limits.h>

int main (void)
{
  int i, j, k;

  i = INT_MIN;
  j = 0 - i / 2;
  k = - i / 2;
  printf ("j = %d\n", j);
  printf ("k = %d\n", k);
  return 0;
}