
GCC should warn about 2^16 and 2^32 and 2^64 - Kliment
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90885
======
ChrisRR
For those who aren't C/C++ programmers, the issue here is people using ^ to
mean power where it means XOR in C/C++.

~~~
quickthrower2
I am not a C programmer but my opinion with any language is don’t try to catch
mistakes like this in the compiler. Instead leave to configurable and
competing linters for people who want to catch possible mistakes like this.
Anyone caught by this mistake probably hasn’t tested their program adequately.
Any mistake induced by the wrong constant number should be easy to weed out
with unit testing.

~~~
DownGoat
Not including a linter in the earlier C compilers are one of the hughe
mistakes of that area. Compilers absolutely should have linters, they are very
valuable tools. Think about all the common security mistakes in your average C
application that could have been avoided over the years with a linter.

I'm pretty sure Dennis Ritchie at some point himself said that not including a
linter was a mistake, but I cannot find a quote of this with a quick search.

~~~
Crinus
Back in the day most people actually ignored the few warnings compilers would
give them, i do not think that having a linter would be used much (and AFAIK
there were some).

~~~
gumby
"Back in the day?" Check out your system's log file for a scary collection of
horror shows. Or compile most packages these days.

In defense: configuring a package that is compiled by lots of people on lots
of machines with lots of versions of various compilers requires a lot of
attention to warning flags and such. If you aren't starting out a package from
a blank buffer it's very hard to get this right.

But I am frequently shocked by the number of compiler warnings I get from code
downloaded from public repos and compiled in precisely the environments it's
been documented to have been tested on.

------
garethrees
This seems like a good idea to me, since there's evidence that programmers are
making this mistake, and the proposal is to add a warning only for the
expressions that are most likely to be mistakes, that is 2^{decimal integer
literal} and maybe also 10^{decimal integer literal}. There are many
constructs that are well-defined in C, but where it is helpful to have
warnings: use of = in condition expressions, implicit fallthrough in switch
statements, misleading indentation, unsafe multiple statement macros, and so
on. Programming in C is hard enough that every bit of compiler support is
valuable.

~~~
mrfredward
The power vs xor mistake is no doubt a common one, but I take issue with the
2^8, 2^16, 2^32 examples that got singled out because they are also common
bitmasks. Should FLAG_BIT1 ^ FLAG_BIT3 really be a warning?

XOR may be rarely used, but 2^8 is not only one of the most common accidental
XORs, it's also probably one of the more common legitimate uses of it.

~~~
tln
> Should FLAG_BIT1 ^ FLAG_BIT3 really be a warning?

Nope, the warning would be for literal numbers in the source. IMO anyone who
doesn't define constants for the flag bits deserves the warning.

~~~
mrfredward
So 2^8 is a warning, but 2^BITS_IN_BYTE is not? I don't think whether or not
the preprocessor helped in making the expression is a good heuristic for
whether or not it is a mistake.

~~~
garethrees
A warning heuristic needs to have a low false positive rate; a low false
negative rate is nice but is not necessary. The purpose of a warning is to
detect some common errors without inconveniencing too many correct programs.
If some other errors go undetected then that is a shame but at least it is no
worse than the current situation.

------
deathanatos
I recently found several instances of hand-crafted for loops in our Python
code with:

    
    
      j = 0
      while condition():
        ++j
    

In Python, there is no "increment" operator, so `++j` is parsed as two unary
plus operators: it's a no-op.

~~~
dagw
I recently found the following bug in some python code at work

    
    
      x = 12 //10
    

What they where apparently trying to do was to change the value of x while
commenting out the old value for reference. Except in python // is integer
division and not comments so x was set to 1 instead of 12.

~~~
alexeiz
This is silly. One of my personal stupid mistakes in Python is forgetting to
delete a trailing comma. The resulting code is still valid, because a trailing
comma produces a tuple.

    
    
        a = b,

~~~
dagw
Or accidentally forgetting a comma like in

    
    
      a = ["long", "list" "of", "strings]
    

which become

    
    
      a = ["long", "listof", "strings"]
    

due to automatic string concatenation

------
nialv7
This is an example of why you shouldn't use blanket warning options like -Wall
in combination with -Werror. Otherwise your program might fail to compile just
because the dev randomly thought of some new things to warn about.

~~~
archi42
We use -Wall and -Wextra, and fixed basically all our warnings. Now everyone
writes virtually warning-free code (that is, any warning is fixed before
committing). And I don't feel limited in what I can do.

We could roll -Werror for most packages (I think we have a few packages, e.g.
3rd party libs, which emit warnings), but only use error=format and
error=format-extra-args.

To be fair, we disable these warnings (-Wno-...): unknown-pragmas, long-long,
register, unused-command-line-argument.

~~~
seba_dos1
I just keep my codebase warning free and check it in CI. No need for -Werror
on package level, users don't need to deal with random breakage from a false-
positive warning.

~~~
archi42
If you don't control the build env (e.g. FOSS work), then of course relying on
-Werror might yield unnecessary trouble.

~~~
marcosdumay
You never completely control your build env. You are always relying on 3rd
parties for some extent.

That may not look relevant in short periods of time, but there are large odds
that somebody will be biten by your choice of using -Werror 5 or 10 years down
the road.

~~~
archi42
I would not sign that claim as a general truth. It's true under some
assumptions, but then, well, just disable -Werror in 5 to 10 years? It's not
like THAT is a breaking change.

OTOH 5 to 10 years is a good way to accumulate plenty of warnings (assuming a
lack of development discipline), which at some point makes it easy to miss
that one critical warning that should really be fixed. Maybe I should mention
the worst case for an error in the code I write is "people die" (static
analysis of safety critical stuff), so that's a good motivation to have no
warnings ;-)

------
typopl
My perl script to scan C/C++ source code for common programming typos can
check for this particular case since 1999.

see
[https://www.cpan.org/authors/id/T/TY/TYPO/typo-2.46.pl](https://www.cpan.org/authors/id/T/TY/TYPO/typo-2.46.pl)

    
    
      // START: Mon Jun 17 14:49:53 2019
      C:\src\test\test.c (1): using ^ on a number 37: short#maxshort=2^16;
      C:\src\test\test.c (2): using ^ on a number 37: int#maxint=2^32;
      C:\src\test\test.c (3): using ^ on a number 37: long#maxlong=2^64;
    

Link to the 1999 Perl Conference paper for the script:

[https://web.archive.org/web/20090729104734/http://www.geocit...](https://web.archive.org/web/20090729104734/http://www.geocities.com/typopl/)

------
TorKlingberg
It would be nice, but I can see it's not easy to come up with a warning
heuristic that doesn't give a bunch of false positives. Sure, 2^16 is
"obviously" wrong, but how about SOMETHING ^ XOR_KEY with #define SOMETHING
and #define XOR_KEY 16?

~~~
DaiPlusPlus
They discuss that in the thread. Consensus seems to be to warn when seeing “2
^ (certain base-10 literals)”.

It’s uncommon to use base 10 when bit-twiddling with the XOR operator - so
this makes sense.

Of course, it would be better if C-family languages didn’t use ^ for XOR in
the first place.

~~~
simias
>Of course, it would be better if C-family languages didn’t use ^ for XOR in
the first place.

I think at the time they were created there simply wasn't an ambiguity in
anybody's mind. POW is a relatively complex operation, I don't think anybody
expected it as a builtin operator (much like SQRT and friends). Arguably so is
DIV but I suppose that's too convenient not to have.

XOR on the other hand is something you really want to be a builtin operator in
a low level, bit-twiddling language like C, so getting a dedicated operator
makes sense. I'm not sure if an other sigil would've made more sense, after
all ASCII lacks ⊕.

~~~
beezle
Algol 68 and Fortran both had __. In fact, COBOL 60 even supported __so not
sure why anyone would not expect it as builtin for C.

------
cryptonector
From the HN submission title it wasn't obvious that the issue is people
misunderstanding that the ^ operator isn't the exponential operator but the
XOR operator. Clicking through made it clear.

Warning about constant subexpressions where the LHS and RHS of ^ are constant
literals makes a lot of sense to me, but if the LHS is a constant expression
but not a constant literal, then not so much. Also, warning about this will
cause some false positives where macro expansions are involved -- probably not
a good thing.

------
ainar-g
Dominik Honnef's staticcheck tool for the Go programming language will
probably warn about these as well[1].

[1]: [https://github.com/dominikh/go-
tools/issues/516](https://github.com/dominikh/go-tools/issues/516).

------
oytis
What if I try to make a pipe with '|' or redirect the result with '>'? Should
there be a warning for that?

I find it amusing that people really do that though.

~~~
sambe
Some people switch programming languages often. Exponentiation operators are
common, both caret and double star are used. It does not seem amusing
(surprising?) to me.

On the other hand, piping and redirection are relatively uncommon outside of
the shell. There is certainly a clearer mental distinction for me between "I
am in shell" and "I am not in shell" than "I should double star".

~~~
oytis
C doesn't have double star either (in fact double star means double
dereferencing).

YMMV or course, but distinction between a low-level language like C, and a
higher-level one that can support exponentiation, matrix multiplication,
thread spawning etc. as a first-class language construct is as clear to me as
the difference between shell and non-shell.

~~~
aidenn0
Someone correct me if I'm wrong, but I believe double star as an infix
operator would be interpreted as multiplication of a dereference:

    
    
      X ** Y
    

would be parsed as

    
    
      X * (*Y)

~~~
bodyfour
...but it's unlikely to be accidentally used as an exponent, since you can't
dereference a number.

------
kazinator
GCC should understand the expression grammars of no fewer than a dozen other
languages and warn you when something could syntactically be an expression
from another language, but with a different meaning.

GCC should also change your diaper, burp you, and issue random diagnostics
like

    
    
      foo.c:32: warning: did you test this yet?

------
kazinator
GCC has gotten too bloated. It could benefit from compile time CONFIG_ options
to remove all the fluff, such as superfluous diagnostics.

If for whatever reason I have to include GCC in an embedded this sort of
"misleading indentation" and "suggest parentheses" nonsense just wastes
precious flash space.

------
NotPaidToPost
I don't think it would not be simple or a good idea to warn because these are
perfectly valid expressions and it would lead to a flood of warnings if
compilers started to display "Did you really mean that?" for an ever growing
list of expressions (which is what it would become).

Better to leave this to code analysis tools.

Edit:

2^32 uses the ^ operator exactly as intended, and has perfectly legitimate
uses, especially when dealing with registers of HW peripherals.

It's not the same as warning on "if (a=b)" as someone replied.

From a language perspective, 2^32 is exactly the same as 2+32.

~~~
rocqua
It's a warning not an error. Moreover, it is very hard to come up with a
legitimate usecase of 2^32 as an expression. People who use it to set bit
flags will use &, and for bit flags, octal or hex notation is probably better.

~~~
NotPaidToPost
> It's a warning not an error.

Many build environments are set to treat all warnings as errors.

The point is that 2^32 is a perfectly compliant C expression that is neither
misleading nor ambiguous, and that also won't create any variable overflow. It
uses ^ exactly as intended. Why should the compiler complain? Why should I get
a warning/error when following the spec to the letter?

~~~
barrkel
Plenty of valid expressions generate warnings. A frequent gotcha is `=` in
boolean contexts. Warnings are justified, and can normally be avoided with a
little bit more lexical work (e.g. an extra set of parentheses). The upside is
large and the downside is miniscule.

~~~
OskarS
Isn't that pretty much the definition of a warning? An expression that is
technically valid, but probably a mistake. If something wasn't a valid
expression, it would be a compiler error, not a warning.

~~~
mikeash
Usually, yes. C is weird because undefined behavior is illegal, can sometimes
be detected statically, and yet will not produce an error. So sometimes you
get warnings for invalid yet error-free code. It’s a strange language.

------
antirez
Terrible idea. If a programmer is so unfamiliar with C/C++ to believe ^ is
pow(), she/he will create a lot of other problems regardless. Without to
mention the kind of bugs created by such incorrect usage would be simple to
spot most of the cases.

~~~
OskarS
Wait... so your point is that since "bad programmers" do this, there shouldn't
be a warning for it? That is among the silliest thing I ever heard. Especially
since there's a trivial way to get rid of the warning: just write "18" instead
of "2^16", if you REALLY intended the xor.

Also: it's incredibly naive to think that "bad programmers" are the only ones
that would make a mistake like this. I'm very familiar with all C/C++
operators and know perfectly well that the caret represents xor, but I could
easily imagine myself slipping and writing 2^16 instead of 1 << 16, because
that's how the rest of the world writes exponentials.

Let he/she who has never written a typo and had the compiler save them cast
the first stone.

~~~
mehrdadn
> Wait... so your point is that since "bad programmers" do this, there
> shouldn't be a warning for it? That is among the silliest thing I ever
> heard.

In all honesty while I don't agree with this particular instance, the
reasoning isn't ridiculous. If we assume it's true that it'd only affect bad
programmers, then you probably wouldn't want to add it, since it'd increase
the false positive risk and/or otherwise potentially get in the way of
everyone else. (Kind of like how you wouldn't make cars start honking when
they're turned on as a means of protecting against bad drivers, even thought
that might well save lives.) Some tools just need to assume some base level of
expertise to be effective.

~~~
mikeash
You snuck in a second premise to the argument: that it will increase the false
positive risk. And if we accept that premise, we don’t need the other one.

Bad programmers are the ones who need the most help from our tools. Saying
there’s no need for a warning because only bad programmers will benefit is
like saying there’s no need for crossing guards because only stupid children
get killed crossing the street.

~~~
estebank
I think you just helped me understand where the objection comes from. The
people against this warning seem to feel infantilized by these type of
warnings, much in the way you're comparing it to crossing guards for children.
My view, and I guess the view of people arguing for these kind of warnings see
them like seatbelts: a mild annoyance that is very much worth it.

~~~
mikeash
Sounds about right. I don’t really get it myself. As a professional C and C++
programmer, every mistake is punished severely by the computer and I want all
the help I can get in avoiding them. Warnings aren’t annoying, what’s annoying
are one-in-a-thousand crashes that only happen on someone else’s computer.

