Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #141843 > unrolled thread
| Started by | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| First post | 2019-03-09 16:53 +0000 |
| Last post | 2019-03-19 14:17 -0700 |
| Articles | 15 on this page of 35 — 13 participants |
Back to article view | Back to comp.lang.c
Remembering C's operator precedence rules Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-03-09 16:53 +0000
Re: Remembering C's operator precedence rules Richard Damon <Richard@Damon-Family.org> - 2019-03-09 15:21 -0500
Re: Remembering C's operator precedence rules Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-03-09 21:41 +0000
Re: Remembering C's operator precedence rules Keith Thompson <kst-u@mib.org> - 2019-03-09 12:32 -0800
Re: Remembering C's operator precedence rules Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-03-09 21:21 +0000
Re: Remembering C's operator precedence rules Richard Damon <Richard@Damon-Family.org> - 2019-03-09 16:42 -0500
Re: Remembering C's operator precedence rules "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2019-03-09 14:01 -0800
Re: Remembering C's operator precedence rules Keith Thompson <kst-u@mib.org> - 2019-03-09 14:17 -0800
Re: Remembering C's operator precedence rules Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-03-10 00:42 +0000
Re: Remembering C's operator precedence rules Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2019-03-09 13:54 -0700
Re: Remembering C's operator precedence rules Bart <bc@freeuk.com> - 2019-03-09 21:37 +0000
Re: Remembering C's operator precedence rules Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-03-09 22:01 +0000
Re: Remembering C's operator precedence rules Richard Damon <Richard@Damon-Family.org> - 2019-03-09 18:59 -0500
Re: Remembering C's operator precedence rules Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-03-13 09:26 -0700
Re: Remembering C's operator precedence rules Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-03-13 10:11 -0700
Re: Remembering C's operator precedence rules Bart <bc@freeuk.com> - 2019-03-13 17:40 +0000
Re: Remembering C's operator precedence rules Keith Thompson <kst-u@mib.org> - 2019-03-13 15:24 -0700
Re: Remembering C's operator precedence rules Bart <bc@freeuk.com> - 2019-03-13 23:43 +0000
Re: Remembering C's operator precedence rules Keith Thompson <kst-u@mib.org> - 2019-03-13 17:43 -0700
Re: Remembering C's operator precedence rules Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-03-18 08:53 -0700
Re: Remembering C's operator precedence rules Wouter Verhelst <w@uter.be> - 2019-03-13 22:24 +0200
Re: Remembering C's operator precedence rules Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-03-13 14:06 -0700
Re: Remembering C's operator precedence rules Ian Collins <ian-news@hotmail.com> - 2019-03-14 14:28 +1300
Re: Remembering C's operator precedence rules scott@slp53.sl.home (Scott Lurndal) - 2019-03-14 13:35 +0000
Re: Remembering C's operator precedence rules Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-03-14 06:55 -0700
Re: Remembering C's operator precedence rules Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-03-14 16:39 +0000
Re: Remembering C's operator precedence rules scott@slp53.sl.home (Scott Lurndal) - 2019-03-14 17:37 +0000
Re: Remembering C's operator precedence rules Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-03-14 20:42 +0000
Re: Remembering C's operator precedence rules Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-03-14 10:42 -0700
Re: Remembering C's operator precedence rules Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-03-14 23:08 +0000
Re: Remembering C's operator precedence rules Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-03-15 02:53 -0700
Re: Remembering C's operator precedence rules Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2019-03-15 17:52 -0600
Re: Remembering C's operator precedence rules Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-03-13 12:56 -0700
Re: Remembering C's operator precedence rules Jens Stuckelberger <Jens_Stuckelberger@nowhere.net> - 2019-03-13 20:14 +0000
Re: Remembering C's operator precedence rules fir <profesor.fir@gmail.com> - 2019-03-19 14:17 -0700
Page 2 of 2 — ← Prev page 1 [2]
| From | Wouter Verhelst <w@uter.be> |
|---|---|
| Date | 2019-03-13 22:24 +0200 |
| Message-ID | <eg5olf-gk.ln1@gangtai.home.grep.be> |
| In reply to | #141938 |
On 13/03/2019 19:11, Tim Rentsch wrote: > Joe Pfeiffer <pfeiffer@cs.nmsu.edu> writes: >> [...], and if I don't remember for sure in my own code > > It isn't hard to remember if one makes an effort to learn. > Fifteen to thiry minutes, tops, and that's a one-time cost. When I was taught C in college, we had to memorize the operator precedence. I tried, I really did. It's not "fifteen to thirty minutes, tops". It took me several hours. I have forgotten most of that since.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2019-03-13 14:06 -0700 |
| Message-ID | <86k1h2qyap.fsf@mailhub.linuxsc.com> |
| In reply to | #141942 |
Wouter Verhelst <w@uter.be> writes: > On 13/03/2019 19:11, Tim Rentsch wrote: > >> Joe Pfeiffer <pfeiffer@cs.nmsu.edu> writes: >> >>> [...], and if I don't remember for sure in my own code >> >> It isn't hard to remember if one makes an effort to learn. >> Fifteen to thiry minutes, tops, and that's a one-time cost. > > When I was taught C in college, we had to memorize the operator > precedence. I tried, I really did. It's not "fifteen to thirty minutes, > tops". It took me several hours. I have forgotten most of that since. Notice that I said learn, not memorize. The key is to find a way to learn without having to resort to rote memorization. Most programmers are better at learning things that have some structure to them rather than just trying to memorize a table of facts. The C operators, and their precedence relationships, have a lot of structure (a lot of which you already know) - these can be learned, and retained, while needing to remember only very little. Please see the long piece I wrote responding to Ben Bacarisse's original posting.
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2019-03-14 14:28 +1300 |
| Message-ID | <getp20Ffe1gU1@mid.individual.net> |
| In reply to | #141942 |
On 14/03/2019 09:24, Wouter Verhelst wrote: > On 13/03/2019 19:11, Tim Rentsch wrote: >> Joe Pfeiffer <pfeiffer@cs.nmsu.edu> writes: >>> [...], and if I don't remember for sure in my own code >> >> It isn't hard to remember if one makes an effort to learn. >> Fifteen to thiry minutes, tops, and that's a one-time cost. > > When I was taught C in college, we had to memorize the operator > precedence. I tried, I really did. It's not "fifteen to thirty minutes, > tops". It took me several hours. I have forgotten most of that since. I just memorised the page number (48) in K&R... -- Ian.
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2019-03-14 13:35 +0000 |
| Message-ID | <VMsiE.8585$q55.1681@fx42.iad> |
| In reply to | #141948 |
Ian Collins <ian-news@hotmail.com> writes: >On 14/03/2019 09:24, Wouter Verhelst wrote: >> On 13/03/2019 19:11, Tim Rentsch wrote: >>> Joe Pfeiffer <pfeiffer@cs.nmsu.edu> writes: >>>> [...], and if I don't remember for sure in my own code >>> >>> It isn't hard to remember if one makes an effort to learn. >>> Fifteen to thiry minutes, tops, and that's a one-time cost. >> >> When I was taught C in college, we had to memorize the operator >> precedence. I tried, I really did. It's not "fifteen to thirty minutes, >> tops". It took me several hours. I have forgotten most of that since. > >I just memorised the page number (48) in K&R... I just use parenthesis to obtain the required precedence. It is subsequently unmistakable as to what the intent was.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2019-03-14 06:55 -0700 |
| Message-ID | <3c994f0a-ddbc-4106-96c5-a362aa29c8ff@googlegroups.com> |
| In reply to | #141953 |
On Thursday, 14 March 2019 13:35:59 UTC, Scott Lurndal wrote: > Ian Collins <ian-news@hotmail.com> writes: > >On 14/03/2019 09:24, Wouter Verhelst wrote: > >> On 13/03/2019 19:11, Tim Rentsch wrote: > >>> Joe Pfeiffer <pfeiffer@cs.nmsu.edu> writes: > >>>> [...], and if I don't remember for sure in my own code > >>> > >>> It isn't hard to remember if one makes an effort to learn. > >>> Fifteen to thiry minutes, tops, and that's a one-time cost. > >> > >> When I was taught C in college, we had to memorize the operator > >> precedence. I tried, I really did. It's not "fifteen to thirty minutes, > >> tops". It took me several hours. I have forgotten most of that since. > > > >I just memorised the page number (48) in K&R... > > I just use parenthesis to obtain the required precedence. It is subsequently > unmistakable as to what the intent was. > You can't use parentheses for everything without making expressions unreadable. Parentheses are useful for the >> and << operators, the bitwise logical operators, and the boolean logical operators. Also for the ? : operator. Sometimes you also need to use on normal arithmetical expressions with mixed terms and factors, to show that the factors are genuinely factors, where this isn't obvious from context. But not everywhere. Unneeded parentheses are useful mainly for bit manipulation, where there isn't a strong convention on precedence or an obvious intuitive precedence.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-03-14 16:39 +0000 |
| Message-ID | <87bm2d76lu.fsf@bsb.me.uk> |
| In reply to | #141953 |
scott@slp53.sl.home (Scott Lurndal) writes: > Ian Collins <ian-news@hotmail.com> writes: >>On 14/03/2019 09:24, Wouter Verhelst wrote: >>> On 13/03/2019 19:11, Tim Rentsch wrote: >>>> Joe Pfeiffer <pfeiffer@cs.nmsu.edu> writes: >>>>> [...], and if I don't remember for sure in my own code >>>> >>>> It isn't hard to remember if one makes an effort to learn. >>>> Fifteen to thiry minutes, tops, and that's a one-time cost. >>> >>> When I was taught C in college, we had to memorize the operator >>> precedence. I tried, I really did. It's not "fifteen to thirty minutes, >>> tops". It took me several hours. I have forgotten most of that since. >> >>I just memorised the page number (48) in K&R... > > I just use parenthesis to obtain the required precedence. It is subsequently > unmistakable as to what the intent was. I hop you won't mind my saying that that's not a very interesting answer! Everyone does that because you have to sometimes. The interesting question is when, exactly when, you would add /redundant/ parentheses. I am pretty sure you don't add them to x = y + 1 z = -sin(theta) 1 + l/2 -b + sqrt(b*b - 4*a*c) (but do say if you would). Here are some others in what I imagine is increasing order of the likelihood of your feeling the need for more parentheses: if (a < b && b < c) ... if (cp < end - 1 && *cp != 0) ... if (cp == end || cp < end-1 && *cp != 0) ... if (cp < end-1 && *cp != 0 || cp == end) ... return *ret_code = NO_SUCH_FILE, ptr; fp = file_exists(name) ? fopen(name, "r") : stdin; result = process(file) || log_error(); result = process(file) && tidy_up() || log_error(); if (1 << n > limit) ... 1 << w-1 & bits (Yes, two of the ifs have the || swapped -- I think it make a difference to some people but I'm not sure.) Do you feel they need some ()s? There's another side to this question -- would you have added redundant parentheses to these if you were writing these from scratch? I know it's hard to answer that having just seem them all without, but writing code when you are not sure is quite different to reading it when you can, at least provisionally, assume that the code means something sane. -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2019-03-14 17:37 +0000 |
| Message-ID | <2jwiE.76034$O65.74368@fx35.iad> |
| In reply to | #141961 |
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>scott@slp53.sl.home (Scott Lurndal) writes:
>
>> I just use parenthesis to obtain the required precedence. It is subsequently
>> unmistakable as to what the intent was.
>
>I hop you won't mind my saying that that's not a very interesting
>answer! Everyone does that because you have to sometimes. The
>interesting question is when, exactly when, you would add /redundant/
>parentheses. I am pretty sure you don't add them to
>
> x = y + 1
>
> z = -sin(theta)
>
> 1 + l/2
>
> -b + sqrt(b*b - 4*a*c)
As you say, the first four don't require parens.
>
>(but do say if you would). Here are some others in what I imagine is
>increasing order of the likelihood of your feeling the need for more
>parentheses:
>
> if (a < b && b < c) ...
>
> if (cp < end - 1 && *cp != 0) ...
>
> if (cp == end || cp < end-1 && *cp != 0) ...
>
> if (cp < end-1 && *cp != 0 || cp == end) ...
I would use parens with the four immediately above.
>
> return *ret_code = NO_SUCH_FILE, ptr;
>
> fp = file_exists(name) ? fopen(name, "r") : stdin;
>
> result = process(file) || log_error();
>
> result = process(file) && tidy_up() || log_error();
I wouldn't have written any of these four the way you have
unless I was writing a korn shell script. In C/C++, I'd use
if sans side effects:
e.g.
result = process(file);
if (result) {
tidy_up();
} else {
log_error();
}
>
> if (1 << n > limit) ...
>
> 1 << w-1 & bits
These I would have used parens (and would likely have use 1u, 1ul or 1ull depending
on the final required width).
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-03-14 20:42 +0000 |
| Message-ID | <875zsl6vcz.fsf@bsb.me.uk> |
| In reply to | #141964 |
scott@slp53.sl.home (Scott Lurndal) writes:
> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>>scott@slp53.sl.home (Scott Lurndal) writes:
>>
>
>>> I just use parenthesis to obtain the required precedence. It is subsequently
>>> unmistakable as to what the intent was.
>>
>>I hop you won't mind my saying that that's not a very interesting
>>answer! Everyone does that because you have to sometimes. The
>>interesting question is when, exactly when, you would add /redundant/
>>parentheses. I am pretty sure you don't add them to
>>
>> x = y + 1
>>
>> z = -sin(theta)
>>
>> 1 + l/2
>>
>> -b + sqrt(b*b - 4*a*c)
>
>
> As you say, the first four don't require parens.
>
>>
>>(but do say if you would). Here are some others in what I imagine is
>>increasing order of the likelihood of your feeling the need for more
>>parentheses:
>>
>> if (a < b && b < c) ...
>>
>> if (cp < end - 1 && *cp != 0) ...
>>
>> if (cp == end || cp < end-1 && *cp != 0) ...
>>
>> if (cp < end-1 && *cp != 0 || cp == end) ...
>
> I would use parens with the four immediately above.
So you consider it confusing, or at least not immediately obvious (to
you or your readers), that relational operators have higher precedence
than && and ||? That one surprises me.
I was hoping you'd add the parentheses. I presume you'd add
if ((cp < end - 1) && (*cp != 0)) ...
if ((cp == end) || ((cp < end-1) && (*cp != 0))) ...
if (((cp < end-1) && (*cp != 0)) || (cp == end)) ...
and no more? I find the last two very fussy.
>> return *ret_code = NO_SUCH_FILE, ptr;
>>
>> fp = file_exists(name) ? fopen(name, "r") : stdin;
>>
>> result = process(file) || log_error();
>>
>> result = process(file) && tidy_up() || log_error();
>
> I wouldn't have written any of these four the way you have
> unless I was writing a korn shell script. In C/C++, I'd use
> if sans side effects:
>
> e.g.
>
> result = process(file);
> if (result) {
> tidy_up();
> } else {
> log_error();
> }
That's another matter. The two bits of code do different things. You
have to do more work to get result set to the correct "success" status.
>> if (1 << n > limit) ...
>>
>> 1 << w-1 & bits
>
> These I would have used parens
Are you OK with '<<' vs. '-' but not '<<' vs. '&'? Or it is both?
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2019-03-14 10:42 -0700 |
| Message-ID | <9531dc30-1822-4da7-9130-784c89afeaf3@googlegroups.com> |
| In reply to | #141961 |
On Thursday, 14 March 2019 16:39:52 UTC, Ben Bacarisse wrote: > > if (cp == end || cp < end-1 && *cp != 0) ... > > if (cp < end-1 && *cp != 0 || cp == end) ... > > (Yes, two of the ifs have the || swapped -- I think it make a difference > to some people but I'm not sure.) Do you feel they need some ()s? > Are you sure you got these right? What happens if cp == end -1 ?
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-03-14 23:08 +0000 |
| Message-ID | <87zhpx5a16.fsf@bsb.me.uk> |
| In reply to | #141965 |
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes: > On Thursday, 14 March 2019 16:39:52 UTC, Ben Bacarisse wrote: >> >> if (cp == end || cp < end-1 && *cp != 0) ... >> >> if (cp < end-1 && *cp != 0 || cp == end) ... >> >> (Yes, two of the ifs have the || swapped -- I think it make a difference >> to some people but I'm not sure.) Do you feel they need some ()s? >> > Are you sure you got these right? What happens if cp == end -1 ? The result is 0, no? If you mean did I write a meaningful expression, probably not, at least I can't imagine what use this expression could be. It was simply intended to an && with || test of some sort. -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2019-03-15 02:53 -0700 |
| Message-ID | <d01a4a05-1d1d-4601-8f8a-cae61a30e676@googlegroups.com> |
| In reply to | #141968 |
On Thursday, 14 March 2019 23:08:45 UTC, Ben Bacarisse wrote: > Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes: > > > On Thursday, 14 March 2019 16:39:52 UTC, Ben Bacarisse wrote: > >> > >> if (cp == end || cp < end-1 && *cp != 0) ... > >> > >> if (cp < end-1 && *cp != 0 || cp == end) ... > >> > >> (Yes, two of the ifs have the || swapped -- I think it make a difference > >> to some people but I'm not sure.) Do you feel they need some ()s? > >> > > Are you sure you got these right? What happens if cp == end -1 ? > > The result is 0, no? If you mean did I write a meaningful expression, > probably not, at least I can't imagine what use this expression could > be. It was simply intended to an && with || test of some sort. > OK. Generally code means something sensible, and that affects whether you need parentheses or not. You can see the meaning of the fragment, and if that happens to match the order without parentheses, you can often leave them out. If the fragment is odd because of weird logic elsewhere in the program, you must be more conservative.
[toc] | [prev] | [next] | [standalone]
| From | Joe Pfeiffer <pfeiffer@cs.nmsu.edu> |
|---|---|
| Date | 2019-03-15 17:52 -0600 |
| Message-ID | <1bsgvnpufp.fsf@pfeifferfamily.net> |
| In reply to | #141969 |
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes: > On Thursday, 14 March 2019 23:08:45 UTC, Ben Bacarisse wrote: >> Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes: >> >> > On Thursday, 14 March 2019 16:39:52 UTC, Ben Bacarisse wrote: >> >> >> >> if (cp == end || cp < end-1 && *cp != 0) ... >> >> >> >> if (cp < end-1 && *cp != 0 || cp == end) ... >> >> >> >> (Yes, two of the ifs have the || swapped -- I think it make a difference >> >> to some people but I'm not sure.) Do you feel they need some ()s? >> >> >> > Are you sure you got these right? What happens if cp == end -1 ? >> >> The result is 0, no? If you mean did I write a meaningful expression, >> probably not, at least I can't imagine what use this expression could >> be. It was simply intended to an && with || test of some sort. >> > OK. Generally code means something sensible, and that affects whether you > need parentheses or not. You can see the meaning of the fragment, and > if that happens to match the order without parentheses, you can often > leave them out. If the fragment is odd because of weird logic elsewhere > in the program, you must be more conservative. The problem is when the meaning seems clear to you, based on misremembering the precedence. That's the sort of bug that takes a *long* time to find.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2019-03-13 12:56 -0700 |
| Message-ID | <86o96er1jf.fsf@mailhub.linuxsc.com> |
| In reply to | #141843 |
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> Prompted by recent posts about remembering C's 15 precedence
> levels for its 49 operators, I thought I would gather together
> some remarks [...]
> So how do you either remember these, or work them out from first
> principles? Do you have any handy mnemonics or idiomatic examples
> to share?
I don't do well at rote memorization. I hardly ever try to
memorize something "by heart", where it's all done just by
memory. In fact, pretty much the opposite - normally I want
to remember as little as possible, and let logic fill in the
rest. Here are my own mnemonic aids for C expression syntax.
Let's forget for a moment about bitwise operators (the shift
operators and the binary logical operators &, ^, |). I don't
need to do anything special to remember how everything else
works: everything goes where I would expect it to go, assuming
The Law of Least Astonishment. Well, almost everything. There
are two wrinkles: casting, and comparisons.
There's a little dance that happens with cast operators and
prefix unary expressions. A cast is _almost_ like a prefix
operator, but there are some exceptions. Fortunately the
exceptions are things that either don't make sense or are
ambiguous. So I don't have to worry about these cases,
because they never come up, or if they do the compiler will
remind me to stay out of those places. Although the syntax
rules separate casts and prefix operators, in practice they
can be treated as the same (perhaps remembering the asterisk
that says "well not exactly").
The splitting of comparison operators into two strata (ordering
and equality/inequality) is suprising. I think though that the
reason it's surprising is just an accident of history (ie, my own
personal history in earlier learning). C doesn't group operators
together (in particular, binary operators) unless they are very
closely related. Ordering comparisons and equality comparisons
are superficially related, but in usage are rather dissimilar.
Consider:
floating point - almost always use ordering comparisons,
only very rarely equality/inequality
pointers - all pointers can be compared for (in)equality;
only some pointers can be compared for order
complex number - equality/inequality allowed; comparing for
relative order is not even allowed
Before learning C I wouldn't have guessed that comparison
operators would occupy two different precedence levels. Now that
I know C, it isn't nearly so surprising, and in fact even almost
natural. Ordering and equality are very different sorts of
relationships. Once I know they are different, which group takes
precedence follows from the law of least astonishment.
Minor digression: I don't have any trouble with the relative
order of &, ^, and |, especially since knowing that they are "low
budget" logical connectives, and therefore underneath the
[in]equality operators, that all fits together nicely, with ==/!=
being "low budget" EQV/XOR logical operators, conveniently on the
other side of & from ^. I also have an example (which believe it
or not came up in actual code) for a separate reinforcement. We
have words (eg, unsigned) w and v, and we want the value in w
updated by v under control of MASK. This expression:
w&MASK ^ w | v&MASK
gives the value desired. (Yes this also could have been done
using ~ and without the ^, but there was some reason not to do
that in the original context.) Note that relative precedence is
reflected in the spacing of the operators/operands: the larger
the number of spaces around an operator, the lower its
precedence. (End of minor digression.)
Now all that's left is what to do with the (binary) bitwise
operators. My device for that is this: the bitwise operators
make a "sandwich" around the comparison operators. I know the
logical operators go underneath because originally C did not
have the short-circuiting logical operators, so the bitwise
operators served as logical connections, and were kept there
for historical reasons. The "sandwich" mnemonic solidifies
the whole picture for me very nicely, which makes it easy
to see how any given expression parses.
These bits and pieces are enough for me. I don't mean to suggest
that they are enough for everyone, especially since different
people have very different learning modes. The key is to find
a set of mnemonic aids that works for _you_. (I am happy to
make specific suggestions if someone gets stuck somewhere.)
Also, one more thing. At some point I adopted the habit of using
spacing to show grouping, both for myself and for other people,
in cases where I thought there might be some uncertainty (and
also other cases, depending). I have found that doing this
reinforces what I have learned, during both the writing of code
and the reading of code. Using (redundant) parentheses to
indicate grouping makes it easy to forget; using spacing to
indicate grouping makes it easy to remember. I recommend leaving
out redundant parentheses in almost all cases, and instead using
spacing to indicate grouping. The result will benefit both you
and your readers.
[toc] | [prev] | [next] | [standalone]
| From | Jens Stuckelberger <Jens_Stuckelberger@nowhere.net> |
|---|---|
| Date | 2019-03-13 20:14 +0000 |
| Message-ID | <q6bobt$2hb$1@news.albasani.net> |
| In reply to | #141843 |
On Sat, 09 Mar 2019 16:53:54 +0000, Ben Bacarisse wrote: > So how do you either remember these, or work them out from first > principles? Do you have any handy mnemonics or idiomatic examples to > share? Sure. I remember the basic ones. For the rest, when in doubt, I either look them up or else I use parentheses.
[toc] | [prev] | [next] | [standalone]
| From | fir <profesor.fir@gmail.com> |
|---|---|
| Date | 2019-03-19 14:17 -0700 |
| Message-ID | <fe1c6bba-e583-4d5a-a404-72b61e57d741@googlegroups.com> |
| In reply to | #141843 |
W dniu sobota, 9 marca 2019 17:54:07 UTC+1 użytkownik Ben Bacarisse napisał:
> I was going to post this as a reply, but once finished I thought it
> should be a new thread.
>
> Prompted by recent posts about remembering C's 15 precedence levels for
> its 49 operators, I thought I would gather together some remarks about
> why I think you can work most of it out for yourself. I certainly don't
> know them all, but I think of them in big blocks (unary, arithmetic,
> relational, and so on) which are easy to relate to each other, and only
> every now and then do I need to consider the structure within these
> blocks of operators.
>
> It's obvious that all the postfix operators will be grouped together in
> one level, as will the prefix operators. What would multiple levels of
> prefix operator even mean? It simply would not make sense to have more
> than one level for each group. Similarly, the two groups must be
> separate. However, which group is higher can be remembered because it's
> natural. Consider
>
> -sin(x)
> *s.member
> &a[1]
>
> You would not want to have to write
>
> -(sin(x))
> *(s.member)
> &(a[1])
>
> to get the desired result for these common forms. If you need another
> clue, remember that -> is provided precisely because you'd have to write
> (*p).member otherwise.
>
> The structure within the arithmetic operators is easy as we all learn it
> in school. You just have to remember to include % as a multiplicative
> operator.
>
> And you can extend that, by analogy, to & binding tighter than | and &&
> tighter than ||. This may be more natural for mathematically inclined
> programmers, but I think the convention is common in electronic
> engineering circles too. The fact that ^ has it's own level between &
> and | is so rarely remembered that it's not one I'd blithely assume
> everyone knows. I never remember it, except when I'm writing things
> like this.
>
> Within the big block of relational operators, another grouping that
> looks odd at first is that == and != have their own precedence level
> just below <, >, <= and >=. This is another case that it's probably
> wise to assume not everyone knows, but /you/ might remember it if you
> consider that == and != make sensible logical connectives, rather like
> && and ||. For example, to test if four variables are in order --
> either ascending or descending -- you can write
>
> a <= b == b <= c == c <= d
>
> Compare that with
>
> a <= b && b <= c && c <= d
>
> for a single order.
>
> There's no reason for the assignment operators to be in more than one
> group, and they must bind very low since almost any expression should be
> permitted without () on the right hand side of an assignment. The
> exception is the comma operator, but again, that's natural. It acts
> like ; for statements so any expression, even assignments, should
> un-parenthesised within a comma expression.
>
> So what's left? Well there's << and >> and the conditional operator.
> These are arithmetic in nature (I'm using the term more loosely here,
> not as in arithmetic vs logical shift) so they will be somewhere in
> amongst *, /, + and so on. However, I need a cue to remember that the
> shift operators come just below addition. The fact that C++ uses them
> for streams does the trick for me. You could not naturally write
>
> std::cout << x + 1
>
> otherwise.
>
> The conditional operator is so different it needs a switch in
> perspective. Because the ? and : can, unambiguously, delimit any
> expression, you can make it fit the pattern of the others if you
> consider ?<exp>: to be a single binary operator. Obviously you want it
> to bind very loosely (below the logical connectives that will often
> occur in the condition), but should it be above or below assignment? To
> work it out, I ask which form is more common:
>
> <cond> ?<exp>: var = val
>
> or
>
> var = <cond> ?<exp>: val
>
> I think I write the second much more than the first, and it is indeed
> that form that needs no parentheses. (As written, the first is a
> constraint violation. To get the assignment /in/ the conditional you
> need to write <cond> ?<exp>: (var = val).)
>
> Finally, is the overall relationship between the big blocks of operators
> logical? By and large I think it is. The unary operators must come
> top, and comma and assignment must come bottom. Between these, the
> arithmetic operators must come above the relational operators, and these
> much come above the logical connectives. The fly in the ointment
> (acknowledged by DMR as an unfortunate import from B) is that &, ^ and |
> sit rather unnaturally low. They were used as logical connectives as
> well as bit-wise operators in B, so it's not too hard to remember that
> they are low, but still, it's not ideal.
>
> So how do you either remember these, or work them out from first
> principles? Do you have any handy mnemonics or idiomatic examples to
> share?
>
> --
> Ben.
i personally dont feel to much need of remembering operator precedence (which is besides easy i think you only need to
remember few things like << is after or before +, if *a is before a++, and so on)
instead i feel another need, need to remember colors to type em from memory
i wrote soem helper procedure for some of my programs
unsigned CL(char* str)
{
int r = 25 - ('z' - str[0]);
int g = 25 - ('z' - str[1]);
int b = 25 - ('z' - str[2]);
unsigned rr = (r*255)/25;
unsigned gg = (g*255)/25;
unsigned bb = (b*255)/25;
return (rr<<16) + (gg<<8) + (bb);
}
it just turns strings lika "zza" "fhg"
into colors "aaa" being black "zzz" being white "zaa" being red "aza" being green and so on..but even with that its hard to remember (hovever i not use it much often
maybe with more practice i would remember
finally
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | comp.lang.c
csiph-web