EmbeddedRelated.com
Forums

Fundamental C question about "if" statements

Started by Oltimer September 20, 2015
On 21/09/15 00:01, Tim Wescott wrote:
> On Sun, 20 Sep 2015 20:42:10 +0200, David Brown wrote: > >> On 20/09/15 19:40, Les Cargill wrote: >>> Oltimer wrote: >>>> >>>> Learning some embedded C using Microchip's C18 Lite. >> >> I hadn't noticed that the OP was using a PIC18. Of course, if you are >> interested in learning about C, programming embedded systems, or simply >> using a half-decent compiler, then pick any microcontroller except a >> Microchip PIC. PICs (and 8051's) should be banned from any beginners on >> the grounds that they cause more harm than good. > > I agree with your two outer statements, but a PIC isn't a bad processor > if you stick to assembly (and projects small enough that assembly is > reasonable). >
The PIC chips have some good points - they are extraordinarily robust. I have worked with a customer's card that had a 85C qualified PIC, and they were looking for ways to push it beyond the 160C or so where it currently stopped working. And once Microchip starts delivering a PIC device, they never seem to obsolete them - you can still buy devices that are 15 years old or more. But they are a horrible CPU to work with - in C or in assembly. At least with assembly you know you are working with something device-specific, so it is less of a surprise.
On 20/09/15 23:39, Les Cargill wrote:
> David Brown wrote: >> On 20/09/15 19:40, Les Cargill wrote: >>> Oltimer wrote: >>>> >>>> Learning some embedded C using Microchip's C18 Lite. >> >> I hadn't noticed that the OP was using a PIC18. Of course, if you are >> interested in learning about C, programming embedded systems, or simply >> using a half-decent compiler, then pick any microcontroller except a >> Microchip PIC. PICs (and 8051's) should be banned from any beginners on >> the grounds that they cause more harm than good. >> >> Get a chip with a Cortex M core, or at least an AVR or msp430. Then you >> can use proper development tools and program in normal C. >> >>> >>> This book: >>> >>> http://www.amazon.com/The-Programming-Language-Brian-Kernighan/dp/0131103628 >>> >>> >>> >>> will save you hours of grief. >> >> It will also cause you hours of grief - because although it is a fairly >> complete guide to C, it is not the best tutorial out there, it is for a >> seriously outdated version of C (C11 is the current standard, though >> there are few practical changes from C99. But C99 is a significantly >> better programming language than ANSI C for most uses), and it >> concentrates on C for big systems - not for embedded systems. >> >> I don't know what the best choice of tutorial is for learning modern >> embedded C, but the oldest known C book is not it. >> >> >> > > > It still works. It's nearly universal. Learning every detailed corner of > the language will take even more time. If you > constrain yourself to mainly K&R plus a couple simple extensions > you will produce more readable code than in any other way. > > Firs learn K&R, then learn the heresies that came later. You > will then know why the heresies are good things. >
I don't expect to change your opinion at all, but I have not the slightest doubt that C99 lets you write clearer, simpler, more efficient, more readable and more logical code than ANSI C, just like ANSI C was a big step up from K&R C. The first edition of The C Programming Language was about K&R C - this should never, ever be taught. The second edition is from 1988, and covers most of what was just becoming ANSI C (the differences between ANSI C, C89 and C90 are minor). That's better, but the world has moved on from 1988. For students of computing history, it is interesting to look at K&R C to see why modern C is better. But for people wanting to learn C for real use, it's about as much use as teaching medical students about blood-letting and prayers to Isis and Osiris before discussing antibiotics. (Okay, that last comparison was a bit exaggerated, but I hope you get my point.)
On 21-Sep-15 12:42 AM, David Brown wrote:
> On 20/09/15 17:14, rickman wrote: >> On 9/20/2015 10:13 AM, David Brown wrote: >>> On 20/09/15 15:30, rickman wrote: >>>> On 9/20/2015 8:13 AM, Oltimer wrote: >>>>> On 20-Sep-15 7:37 PM, David Brown wrote: >>>>>> On 20/09/15 13:22, Oltimer wrote: >>>>>>> >>>>>>> Learning some embedded C using Microchip's C18 Lite. >>>>>>> >>>>>>> >>>>>>> I tried the following and it misbehaved: >>>>>>> >>>>>>> if( 10 < my_variable < 20 ) >>>>>>> { //do this......} >>>>>>> >>>>>>> >>>>>>> >>>>>>> Using the following works: >>>>>>> >>>>>>> if (( x > 10) & ( x < 20)) >>>>>>> { //do this.....} >>>>>>> >>>>>>> >>>>>>> >>>>>>> Is it normal that C cannot handle complexities such as "a < b < c" ? >>>>>>> I would have thought a compiler could easily work out what was >>>>>>> intended. >>>>>>> >>>>>>> Thanks. >>>>>> >>>>>> No, compilers cannot work out something like "a < b < c" - it is >>>>>> interpreted as though it were "(a < b) < c", where "(a < b)" is >>>>>> either 0 >>>>>> or 1. A compiler is merely a computer program that follows set >>>>>> rules - >>>>>> it is not human, and cannot apply common sense to interpret what you >>>>>> write. >>>>>> >>>>>> Your second version is also wrong. In C, the "&" operator is a >>>>>> bitwise >>>>>> and - what you want is a logical and which is "&&". In a number of >>>>>> circumstances, such as this one, they have the same logical effect - >>>>>> but >>>>>> don't make that mistake. Learn the difference, and use the correct >>>>>> version. (The same applies to bitwise or | and logical or || ). >>>>>> >>>>>> So the correct version is : >>>>>> >>>>>> if ((x > 10) && (x < 20)) { >>>>>> // Do this... >>>>>> } >>>>>> >>>>>> You'll get the hang of it - just don't assume C is normal mathematics, >>>>>> and be careful to be accurate about what you write. >>>>>> >>>>> >>>>> >>>>> Thanks David. The reassurance I'm on the right track is good. >>>>> >>>>> Yes, looking at it I can see that it should be "&&" >>>> >>>> Confusing & with && is a common mistake as is mixing = with ==. Both >>>> can be hard to debug too. >>>> >>> >>> Make heavy use of whatever warnings your compiler can give you - gcc >>> with lots of warnings can pick up on many such cases. >> >> Yeah, another common mistake is thinking warnings are just "warnings". >> Code so that there are none. >> > > Agreed - warnings are an indication that you've got something wrong, or > at least risky, in your code (or an indication that you've got a poor > quality compiler that has silly ideas about warnings!). The more you > can find out at compile-time, rather than run-time (or after delivery > time), the better. > > In this case, "-Wall" in gcc includes "-Wparentheses" which warns about > "a < b < c", and also something like "if (x = y) { ... }". "-Wall" also > includes "-Wunused-value", which is commonly triggered if you write > something like "x == y;" instead of "x = y;". > > Of course, the OP may be using a compiler other than gcc, though gcc is > increasingly common - other compilers will typically also have warnings > for that sort of basic mistake. >
Following your advice on compiler warnings paid off - another little bug fixed! Cheers.
On 21/09/15 01:29, Tim Wescott wrote:

> > Whoops #1: I mostly program in C++ these days, and missed the > introduction of stdbool.h. Bad me.
_Bool in C99 onwards is not quite as strong as bool in C++, but it is not bad - and better than using an int or unsigned char in C (since converting to a _Bool is guaranteed to give 0 or 1). But _Bool is one of the reasons why C99 is a better language than ANSI C. (It was one of the C++ features that C99 copied.)
> > Whoops #2: 0 and 1 only? Good! This wasn't always the case, or at least > about 30 years ago there was a compiler (Borland or Microsoft, can't > remember which) that used 0 and -1 (or at least 0xffff). >
The "true" result of a relational operator is guaranteed to be 1 in C11, and I think also in C99. I can't say if it had the same guarantee in earlier C standards. And whether or not the standards say 1 is the value for true, compiler implementations have not always been loyal to that. What is certainly true is that for people who made their own boolean types (pre-C99), there has been a certain amount of variety in the values they used for true and false. 1 and 0 are common, as are -1 and 0, but sometimes people have used different values. Just to be really entertaining, some people used 0 for true and 1 for false.
> Whoops #3: I was thinking of Walter, and your name dribbled off my > fingertips. Oh well.
I believe - but cannot confirm - that there are other people involved in commercial embedded compiler development that also follow this group without making their presence known. If that means that these compiler developers listen to some of the problems and desires of embedded developers, then I guess that's a good thing. But I think Walter is the only open, active member of this group that contributes to discussions and makes it clear that he is a compiler developer. He is always worth listening to.
> > Thank you very much for _all_ the corrections -- I hate to be > responsible for misleading people, so I appreciate it when people see my > mistakes and nudge me back into line. >
Usenet is a self-correcting medium. The fact that we can correct each other is what gives us the freedom to write these posts, knowing that is unlikely that our mistakes will do much damage - thus we can give good advice without worrying too much about the risks of errors.
On 21/09/15 10:36, Oltimer wrote:

> > Following your advice on compiler warnings paid off - another little bug > fixed! >
Glad to help. If more people used gcc warnings properly, there would be a lot less bugs in the world! I'd also recommend -Wextra, and looking through the list of additional warnings - there are many that can be useful.
On 2015-09-20, Tim Wescott <tim@seemywebsite.com> wrote:
> > Any C compiler that targets an 8-bit PIC is not the best for learning -- > at least not for learning C. The PIC architecture is a very bad fit to > the C virtual machine, and as such a compiler writer is forced to choose > between making a compiler that is not compliant to the standards, or > making a compiler that generates hugely inefficient code. >
It's also very resource limited by today's standards.
> I can't speak to the XC8 compiler, but the C18 not only wasn't > compatible, it pretty much required you to do Really Bad Things in order > to get the most efficient code (this, by the way, is the same problem > exhibited by the 8051 -- it's a totally different architecture from the > PIC, but it misses the C virtual machine by a similar-sized mile). > > Given that you can get ARM Cortex-M0 parts that are nearly as small as > the smallest 8-bit parts, and are nearly as cheap (I think they get down > to $0.75 or less in onsies from DigiKey), I don't see any reason not to > use a part that's a better fit to the language. >
The PIC18 has one thing going for it and that is it's available in PDIP so it's easy to breadboard them. Until the PIC32 came along, it was also the only MCU range to have a USB device capability in a PDIP format so that made it of natural interest for some people wanting to do USB work. I've played with the PIC18 in the past and I _really_ disliked it, but it was the only viable option for PDIP based USB device MCUs at the time so I stuck with learning it instead of tossing it on the scrap heap where it belongs. I designed a library at the time which was designed to be portable but needed to include the PIC18, so I made some decisions I wasn't happy about even at the time and which made the code more cumbersome than it needed to be. This was mainly due to the limited resources on the PIC18. The irony is that I never even got the library actually ported to the PIC18 due to other things coming up. :-) I'm now revisiting that work for another reason and it didn't take me long to decide to dump the PIC18 style API for that library and to redo the API on the assumption that more resource rich MCUs are available instead. The reason I am mentioning this is to suggest to the OP that they rethink the choice of PIC18, even for hobbyist use, in 2015. BTW, does anyone actually use PIC18s for new production quality projects these days ? [In this discussion, I'm treating the PIC24 as an extension of the PIC18 but also as something that comes across as an evolutionary dead-end. The PIC24 is even more poorly supported than the PIC18 for open source or hobbyist work; at least the PIC18 has SDCC available for it.] Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world
On 21-Sep-15 5:02 PM, David Brown wrote:
> On 21/09/15 10:36, Oltimer wrote: > >> >> Following your advice on compiler warnings paid off - another little bug >> fixed! >> > > Glad to help. If more people used gcc warnings properly, there would be > a lot less bugs in the world! > > I'd also recommend -Wextra, and looking through the list of additional > warnings - there are many that can be useful. > >
Thanks I'll do some reading on Wextra.
On 21-Sep-15 7:06 PM, Simon Clubley wrote:
> On 2015-09-20, Tim Wescott <tim@seemywebsite.com> wrote:
<snip>
> > The reason I am mentioning this is to suggest to the OP that they > rethink the choice of PIC18, even for hobbyist use, in 2015. > > BTW, does anyone actually use PIC18s for new production quality projects > these days ? >
I've seen PIC18's in commercially made medical/dental chairs (controlling tilt/angle etc) and in some small speed controllers. I guess "quality" is in the eye of the designer! ;)
> [In this discussion, I'm treating the PIC24 as an extension of the PIC18 > but also as something that comes across as an evolutionary dead-end. > The PIC24 is even more poorly supported than the PIC18 for open source > or hobbyist work; at least the PIC18 has SDCC available for it.] > > Simon. >
On Sun, 20 Sep 2015 14:17:34 -0500, Tim Wescott wrote:

> the C compiler -- per its specification -- interprets it as > > if ((10 < my_variable) < 20) > { etc. } > > (or it interprets it as if (10 < (my_variable < 20)) -- I'm not sure > which, if either, is insisted upon).
A.2.1: (6.5.8) relational-expr: shift-expr relational-expr < shift-expr relational-expr > shift-expr relational-expr <= shift-expr relational-expr >= shift-expr IOW, relational operators are left-associative: a<b<c is parsed as (a<b)<c. More generally, assignments are right-associative, all other binary operators are left-associative.
David Brown wrote:
> On 20/09/15 23:39, Les Cargill wrote: >> David Brown wrote: >>> On 20/09/15 19:40, Les Cargill wrote: >>>> Oltimer wrote: >>>>> >>>>> Learning some embedded C using Microchip's C18 Lite. >>> >>> I hadn't noticed that the OP was using a PIC18. Of course, if you are >>> interested in learning about C, programming embedded systems, or simply >>> using a half-decent compiler, then pick any microcontroller except a >>> Microchip PIC. PICs (and 8051's) should be banned from any beginners on >>> the grounds that they cause more harm than good. >>> >>> Get a chip with a Cortex M core, or at least an AVR or msp430. Then you >>> can use proper development tools and program in normal C. >>> >>>> >>>> This book: >>>> >>>> http://www.amazon.com/The-Programming-Language-Brian-Kernighan/dp/0131103628 >>>> >>>> >>>> >>>> will save you hours of grief. >>> >>> It will also cause you hours of grief - because although it is a fairly >>> complete guide to C, it is not the best tutorial out there, it is for a >>> seriously outdated version of C (C11 is the current standard, though >>> there are few practical changes from C99. But C99 is a significantly >>> better programming language than ANSI C for most uses), and it >>> concentrates on C for big systems - not for embedded systems. >>> >>> I don't know what the best choice of tutorial is for learning modern >>> embedded C, but the oldest known C book is not it. >>> >>> >>> >> >> >> It still works. It's nearly universal. Learning every detailed corner of >> the language will take even more time. If you >> constrain yourself to mainly K&R plus a couple simple extensions >> you will produce more readable code than in any other way. >> >> Firs learn K&R, then learn the heresies that came later. You >> will then know why the heresies are good things. >> > > I don't expect to change your opinion at all, but I have not the > slightest doubt that C99 lets you write clearer, simpler, more > efficient, more readable and more logical code than ANSI C, just like > ANSI C was a big step up from K&R C.
No doubt. But still - I think it's somehow important to understand the evolution of the language.
> The first edition of The C > Programming Language
I would not use the first edition.
> was about K&R C - this should never, ever be > taught.
I would not think so; no. 1989 is now 36 years ago. I would agree that that is far back enough. The idiom: void x(y) int y; { } is clunky enough to die right 20 years ago. I probably didn't even spell that right.
> The second edition is from 1988, and covers most of what was > just becoming ANSI C (the differences between ANSI C, C89 and C90 are > minor). That's better, but the world has moved on from 1988. >
To clarify I do mean the second edition or better. I do not care for the belief that there needs to be one way to teach something for "newbies" and another for the advanced class. Besides, the K&R book is a signal example of technical writing.
> For students of computing history, it is interesting to look at K&R C to > see why modern C is better. But for people wanting to learn C for real > use, it's about as much use as teaching medical students about > blood-letting and prayers to Isis and Osiris before discussing antibiotics. >
:)
> (Okay, that last comparison was a bit exaggerated, but I hope you get my > point.) > >
I might have actually have used that *to teach* medical students, partly to make a point about people using appeals to bad statistical analysis as if they were prayers to Osiris. We do see a fair amount of despair-inducing examples of this in real life. -- Les Cargill