EmbeddedRelated.com
Forums
Memfault Beyond the Launch

C program flow control - Very Basic Question.

Started by Royston Vasey June 2, 2010
On 2010-06-02, David Brown <david.brown@hesbynett.removethisbit.no> wrote:
> D Yuniskis wrote: >> Hi Tim, >> >> Tim Wescott wrote: >>> Exception handling in object-oriented programming is specifically >>> designed to address the problems in C++ that C's "goto" and long >>> branch (long goto? I can't remember what it's called) solve in C. >> >> setjmp()/longjmp()? > > People who are allergic to "goto" in C should run screaming at the sight > of these functions!
:) Using setjmp()/longjmp() to handle exceptions is far harder to understand (and in my experience causes many more bugs) than using goto for the same thing.
> There are times when "goto" is the best way to structure your code - > I've used it a few times. You have to be careful with it, as it's easy > to write spaghetti code and lose track of things like variable > initialisations (C++ is fussier about when you are allowed to use it). > But setjmp() and longjmp() are far worse - if you think you need them, > you are almost certainly wrong and should re-structure your code. (If > you /know/ you need them, it's a different matter - few rules in C > programming are absolute.)
Don't use scanf() is pretty close to one of the absolute rules. ;) -- Grant
"D Yuniskis" <not.going.to.be@seen.com> wrote in message 
news:hu5tr8$qpk$1@speranza.aioe.org...
> Hi Royston, > > Royston Vasey wrote: >> I've got a very basic question guys, I'm teaching myself C using >> Microchip's C18 compiler. > > Great! > >> I've got my main loop running, looking for certain conditions to occur, >> receiving a serial command & processing it. >> >> I need to monitor a few things for a time out condition, to do this I'm >> pre-loading Timer1 with the required values and when the timer overflows >> it jumps to the relevant interrupt. > > What are you timing? I.e., are you trying to prevent the > code from waiting for a received character indefinitely? > Or, trying to abort a system call after a certain time limit > is exceeded? etc. > >> All the above works fine. >> >> When the Timer1 interrupt fires what is the easiest/best/correct way to >> execute a block of "reset" code and then recommence execution at a >> _particular_ place in the main() loop? > > <frown> You (typically) can't just jump around your code > "willy nilly" -- unless you really know what's going on under > the hood (doubtful if you're just learning). > > E.g., when the IRQ is signalled, *something* was being done > at that time. That "something" has to be considered when > you decide to *abandon* it (by jumping to a *particular* > place in the main() loop). > > If, for example, the code was busy *deep* in some nested > function call -- lots of cruft on the stack -- and you > just "jumped" to someplace else to "resume execution", > then you have all that cruft still sitting on the stack > with nothing to unroll it. (what happens if the *next* > interrupt does the exact same thing? and the one after > that? i.e., you eventually "blow the stack" because you've > never cleaned its previous contents off of it) > > Even if you were lucky enough to be able to perform the > jump without consequence, you can't jump to any arbitrary > point in "main()" -- because you don't know what the > prerequisites for that part of main happen to be. > Consider, what would you expect the code to do if you jumped > into the middle of a "for" loop? > > If you are building an application that relies on a simple > while loop for it's structure, then you have to poll every > "event" of interest in that loop and "dispatch" accordingly > *from* that loop. Your interrupt has to be "invisible" > to the application (in terms of how it *immediately* > affects program flow). > > If you want to implement a simple timeout, try something like: > - set a (volatile) flag (*bit*!) someplace "common" > - have the ISR *clear* that flag when it occurs > - have whatever "service" you are trying to "time" > poll that flag along with whatever else it is supposed > to do; if it sees the flag get cleared "magically", the > service returns an error (TIMEOUT) instead of success > > So, if you wanted to put a timeout on how long you would > wait for a character to be received: > > result > receive_character(char *character, boolean *flag) { > while (*flag == SET) { > if (check_UART_for_character() == TRUE) { > *character = get_UART_character(); > return SUCCESS; > } > return FAILURE; > } > > I.e., as long as the flag is still *set*, keep checking the > UART to see if a character is available. If so, return the > character *and* indicate "SUCCESS". > > However, once the flag is NOT "SET", stop checking the > UART and just return a FAILURE (TIMEOUT) indication. > > Your main() then does something like: > > // setup hardware > boolean waiting; > > ... > while (FOREVER) { > char character; > ... > start_timer(&waiting, time_limit); > if (receive_character(&character, &waiting) == SUCCESS) > // do something with "character" > else > // character didn't show up in the prescribed time limit > ... > } > > void > start_timer(boolean *flag, timeout_t timeout) { > *flag = SET; > set_hardware_timer(timeout); > } > > and your ISR does: > > void > ISR(void) { > // diddle with the hardware > waiting = ~SET; > } > > (I've not proofed this for typos :< ) > >> Using assembly I would have used "goto" to steer execution where I wanted >> it, but how is it approached in C?
Whew! Thanks for all of the replies guys - the time you put into helping me out really is appreciated. I think I'll go with Don's suggestion - in hindsight it's a little obvious that this is what I should do. Thanks also Tim, Joseph, Hamilton. I once read somewhere that if you can write in assembler then C should be easy - either I misunderstood or whoever said it was WRONG! :) Now to implement it! cheers Royston
Hi Royston,

Royston Vasey wrote:
> I once read somewhere that if you can write in assembler then C should be > easy - either I misunderstood or whoever said it was WRONG! :)
The problem you are having is that C hides a bit more of the hardware from you that ASM would. E.g., in ASM, you would be more aware of what's on the stack, etc. You wouldn't do something like: MAIN: ... CALL FOO ... FOO: CALL BAR ... BAR: CALL BAZ ... BAZ: JUMP MAIN (because you'll munge the stack!)
> Now to implement it!
In article <-Nqdnb42dZ740JvRnZ2dnUVZ_tydnZ2d@westnet.com.au>,
Royston Vasey <royston@vasey.com> wrote:
>I've got a very basic question guys, I'm teaching myself C using Microchip's >C18 compiler.
Although this is c.l.e I would recommend using Turbo C 2.0 to learn C. If you can get it. No distraction from the language itself.
> >Thanks.
Groetjes Albert -- -- Albert van der Horst, UTRECHT,THE NETHERLANDS Economic growth -- being exponential -- ultimately falters. albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst
"Albert van der Horst" <albert@spenarnc.xs4all.nl> wrote in message 
news:l3gfns.fy5@spenarnc.xs4all.nl...
> In article <-Nqdnb42dZ740JvRnZ2dnUVZ_tydnZ2d@westnet.com.au>, > Royston Vasey <royston@vasey.com> wrote: >>I've got a very basic question guys, I'm teaching myself C using >>Microchip's >>C18 compiler. > > Although this is c.l.e I would recommend using Turbo C 2.0 to learn > C. If you can get it. No distraction from the language itself. > >> >>Thanks. > > Groetjes Albert > > -- > -- > Albert van der Horst, UTRECHT,THE NETHERLANDS > Economic growth -- being exponential -- ultimately falters. > albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst >
Thanks Albert, but I'm using C18 as my objective is to created an embedded device and the direct route suits me best.
"D Yuniskis" <not.going.to.be@seen.com> wrote in message 
news:hu7j6t$1q8$1@speranza.aioe.org...
> Hi Royston, > > Royston Vasey wrote: >> I once read somewhere that if you can write in assembler then C should be >> easy - either I misunderstood or whoever said it was WRONG! :) > > The problem you are having is that C hides a bit more of the > hardware from you that ASM would. > > E.g., in ASM, you would be more aware of what's on the stack, etc. > You wouldn't do something like: > > MAIN: > ... > CALL FOO > ... > > > FOO: CALL BAR > ... > > > BAR: CALL BAZ > ... > > > > BAZ: JUMP MAIN > > (because you'll munge the stack!) > >> Now to implement it!
That's true. I guess the advantage of C when I become more conversant will be the speed of getting code up & running.
> >"D Yuniskis" <not.going.to.be@seen.com> wrote in message >news:hu7j6t$1q8$1@speranza.aioe.org... >> Hi Royston, >> >> Royston Vasey wrote: >>> I once read somewhere that if you can write in assembler then C should
be
>>> easy - either I misunderstood or whoever said it was WRONG! :) >> >> The problem you are having is that C hides a bit more of the >> hardware from you that ASM would. >>
<snip>
>>> Now to implement it! > >That's true. I guess the advantage of C when I become more conversant will
>be the speed of getting code up & running. > >
Changing platforms (different processor etc.) becomes a lot easier, especially if you abstract the hardware properly. (HAL) --------------------------------------- Posted through http://www.EmbeddedRelated.com
On Fri, 4 Jun 2010 12:08:28 +0800, "Royston Vasey" <royston@vasey.com>
wrote:

>"Albert van der Horst" <albert@spenarnc.xs4all.nl> wrote >> Royston Vasey <royston@vasey.com> wrote: >> >>> I'm teaching myself C using Microchip's C18 compiler. >> >> Although this is c.l.e I would recommend using Turbo C 2.0 to learn >> C. If you can get it. No distraction from the language itself. > >Thanks Albert, but I'm using C18 as my objective is to created an embedded >device and the direct route suits me best.
I get that you want to dive into hardware, but you'd really be better off learning the language *before* you try to use it for an embedded project. The problem with C is that it _looks_ simple - the truth is that it will be quite a while before you will be able to write reliable programs. Compilers for small MPUs, DSPs and PICs (the generic "PIC") tend to have non-standard features, weird limitations and just more plain old bugs than compilers for popular desktop OSes. And cross-compiling for an embedded target creates build and test issues that desktop systems don't have. All these things are confusing distractions that you don't need while you're trying to learn a language. There are decent, free compilers available for just about any OS. Except for GCC, most won't be C99 compilers, but any ANSI compiler will do for learning. George
On Wed, 02 Jun 2010 08:35:24 -0600, hamilton <hamilton@nothere.com>
wrote:

>On 6/2/2010 6:24 AM, Royston Vasey wrote:
>> Using assembly I would have used "goto" to steer execution where I wanted >> it, but how is it approached in C? > >There is no "goto" in C. > >"goto" in C is bad (very bad) practice.
Up to the 1960's usually the only way to alter the program execution was some kind of jump/branch/goto instructions and some primitive loop constructs on some high level languages (such as the DO loop in Fortran IV), thus gotos had to be used almost exclusively. With languages containing some structured features that are easy to use, the need for gotos was significantly reduced, but not eliminated completely. The C-language lacks several features such as loop naming (allowing exiting multiple nested loops at once) or switch/case style error handlers at the end of module and thus gotos are still required. I would consider the slogan "goto considered harmful" as a harmful statement, since applying it blindly has created a lot of unreadable and hence unmaintainable code (such as weird status variables or very deeply nested if-statements) instead of using one or two well placed gotos to simplify the program structure. After all the Dijkstra/Wirth slogan "goto considered harmful" was intended to advocate the structured programming model and languages based on that model.
George Neuner wrote:
> On Fri, 4 Jun 2010 12:08:28 +0800, "Royston Vasey" <royston@vasey.com> > wrote: > >> "Albert van der Horst" <albert@spenarnc.xs4all.nl> wrote >>> Royston Vasey <royston@vasey.com> wrote: >>> >>>> I'm teaching myself C using Microchip's C18 compiler. >>> Although this is c.l.e I would recommend using Turbo C 2.0 to learn >>> C. If you can get it. No distraction from the language itself. >> Thanks Albert, but I'm using C18 as my objective is to created an embedded >> device and the direct route suits me best. > > I get that you want to dive into hardware, but you'd really be better > off learning the language *before* you try to use it for an embedded > project. The problem with C is that it _looks_ simple - the truth is > that it will be quite a while before you will be able to write > reliable programs. > > Compilers for small MPUs, DSPs and PICs (the generic "PIC") tend to > have non-standard features, weird limitations and just more plain old > bugs than compilers for popular desktop OSes. And cross-compiling for > an embedded target creates build and test issues that desktop systems > don't have. All these things are confusing distractions that you > don't need while you're trying to learn a language. > > There are decent, free compilers available for just about any OS. > Except for GCC, most won't be C99 compilers, but any ANSI compiler > will do for learning. > > George
I disagree with that advice. Programming C on a "big system" and programming C on an embedded system are very different. People who have learned C by reading books (or doing courses) and programming on Windows, Linux, or whatever, often have a lot of unlearning to do before they can write decent embedded software. They'll use "int" everywhere with no consideration for the underlying cpu and they'll use floating point, memory space, "printf" and "malloc" as though they were as cheap as on a PC. They will miss out all understanding of interrupts, volatiles, hardware access, resource limitations, etc. I'd agree that the PIC's (at least, the small PIC's) are awkward devices to learn and have a lot of idiosyncrasies. My recommendation here is simply to drop the PIC and choose a better microcontroller. But if you want to learn programming microcontrollers, learn with microcontrollers.

Memfault Beyond the Launch