Help required

Eep! Sounds like a compiler issue. Your solution falls under the category of "compiler-specific optimisation", which I'd argue was an entirely different issue from "good design".

Again, probably compiler-specific. I have no big problem with this: I've used jump tables in assembler, and I routinely use function tables in C.

FWIW, I'm more defending pure structured design than I am promoting pure C. I used to design in structured English, and code in assembler. Nowadays I use C for both purposes, but I'm still very cautious about separating design from code, if you see what I mean.

Steve

formatting link

Reply to
Steve at fivetrees
Loading thread data ...

... snip ...

Which is even more descriptive as:

void Fuction() { if (CarryOutSomeTask()) { do; some; actions; } else { cleanup; after; failure; } do; some; cleanup; that needs done; regardless; of success; }

Yet I am an advocate of goto in the appropriate places, which are fairly rare.

--
fix (vb.): 1. to paper over, obscure, hide from public view; 2.
to work around, in a way that produces unintended consequences
 Click to see the full signature
Reply to
CBFalconer

[... re: goto ...]

These are both poor examples.

I don't recall ever writing a goto in embedded code, but there was a time when I was implementing desktop APIs (to control embedded systems). The APIs generally took the classic form of files: open the device, perform some operations, close the device when finished.

The open functions tended to be somewhat complex. Ideally, they would be a matter of allocating the required data structures, filling them in, and returning a "handle" to the descriptor which the user would pass in to the operating functions to identify the device. Oftentimes the required data structures were complex, and depended on configuration information in external files or the availability of attached hardware. And of course, memory allocation can fail at any time.

So you wind up with something like

Device_Handle *Device_Open() { Device_Handle *p = NULL;

if () { p = malloc(sizeof(Device_Handle)); if (p) { p->some_substructure = create_sub(); if (p->some_substructure) { p->etc = create_etc(); if (!p->etc) { cleanup_substructure(p->some_substructure(); cleanup_Handle(p); p = NULL } } else { cleanup_Handle(p); p = NULL; } } } return p; }

or (sometimes cleaner and easier to understand):

Device_Handle *Device_Open() { Device_Handle *p = NULL;

if () goto error_exit;

p = malloc(sizeof(Device_Handle)); if (!p) goto error_exit;

p->some_substructure = create_sub(); if (!p->some_substructure) goto error_exit;

p->etc = create_etc(); if (!p->etc) goto error_exit;

return p;

error_exit: if (p) { if (p->some_substructure) cleanup_substructure(p->some_substructure();

cleanup_Handle(p); } return NULL; }

The second solution reduces the amount of duplicate code and gives the code a more linear structure that is easier to understand. IMHO, anyway. The difference is greater the more substructures you have to create and/or initialize.

Regards, -=Dave

--
Change is inevitable, progress is not.
Reply to
Dave Hansen

Heh. A C++ coder would say this is an ideal candidate for a throw/exception. In C, I'd he happy with your code - so long as the error_exit code explicitly avoids any assumptions (as yours does - although I think I'd add cleanup for p->etc as a defence against future expansion, even though it's not needed in your example).

My version (left entirely to my own devices, and I'll explain my aims shortly) would be:

Device_Handle *Device_Open( ) { Device_Handle *p; Boolean ok = TRUE;

if ( ) return( NULL );

p = malloc( sizeof( Device_Handle )); if ( p == NULL ) return( NULL );

// p known to exist from here on in: make sure we stay in a consistent state: p->some_substructure = NULL; p->etc = NULL;

if ( ok ) // defensive { if ( ! ( p->some_substructure = create_sub() )) ok = FALSE; }

if ( ok ) { if ( ! ( p->etc = create_etc() )) ok = FALSE; }

// Cleanup any errors arising: if ( ! ok ) { if ( p->some_substructure != NULL ) cleanup_substructure( p->some_substructure ); if ( p->etc != NULL ) cleanup_etc( p->etc ); cleanup_Handle( p ); }

return(( ok ) ? p : NULL ); }

My aim throughout is to remove future traps (those assumptions that, while valid at the time, come back and bite you later when the code gets expanded). I'm trying to decouple what's happening now from what I have to do later. Yes, I'm having to do some unwinding, but it's all in one place - no duplication (ok, there's the returns and the flag setting/testing... but they're cheap, explicit, and defensive). I'm also creating a template to make it easily expandable - I'm being very explicit, and providing obvious slots to add things later.

I should probably add that my "style" comes from having had to maintain codebases (alone or in teams) over long periods (in some cases, a couple of decades). I'm acutely aware that I (or some other sucker) will come back to this, add something, and maybe break it in the process. So I've developed a defensive style that tries to anticipate the traps I may be laying for myself.

Disclaimer: it's late, and I'm tired, so I hope to Dog I've made no logical errors. I'm *so* gonna get jumped on if I have ;).

Steve

formatting link

Reply to
Steve at fivetrees

Bumsbumsbums. The test should be inverted. I plead insanitary.

Steve

formatting link

Reply to
Steve at fivetrees

Realised I'd replied badly. The "common myth" referred to your first sentence (GOTO saving loads of memory and improving readability).

The second part, I agree with strongly. I can live with GOTOs where they are equivalent to a return or a break - i.e. they don't break structure. Once one gets into spaghetti code, though, all bets are off. The acid test is when you don't quite know how you got here - if you don't know your context (or can't deduce it), you're in deep trouble. I believe this to be unarguably true.

Steve

formatting link

Reply to
Steve at fivetrees

Is that like "I sing the body electric"?

Reply to
larwe

No. Or possibly yes. Or possibly vice-versa.

See? told you I was tired.

Steve

formatting link

Reply to
Steve at fivetrees

Tired? My book ms. is due to the publisher on Friday, and I'm still working on the edits people sent in. I guesstimate another 10K words to write based on the notes I'm reading here.

I have a calculus exam on Thursday afternoon for which at least cursory revision is necessary.

I have a board to bring up by Monday, which is arriving via FedEx tomorrow. It's the (hopefully) final spin of a commercial product, and it contains essentially untested changes.

I have a 2500 word article due in about two weeks (part 5 of my "mad Mac mini" series).

I need to outline the next two articles in my Kuro Box x86-to-PPC migration series and start work on the next one.

I need to dream up scripts for the first couple of episodes of a technical Internet radio broadcast, and find enough of my studio equipment to record at least one of them. Deadline, 5/5.

This is not even counting the people who have contacted me in the past four weeks asking if I could quote them to work on a project... some of them got really insistent when I said I'm >125% loaded at this time. One company sent me a half-case of wine (not bad stuff) with a request to consider scheduling in their project when possible. Not sure how wine is supposed to help with that ;)

I guess this qualifies as a busy week. By Monday I'll either be completely caught up with the immediate requirements, or I'll have a heart attack.

Reply to
larwe

(-- clip clip --)

Here's an example with a modern C compiler (GCC 3.4.3, ARM):

/* copy.c - memcpy() loop in C */ /* Tauno Voipio */

void copy(const unsigned char *src, unsigned char *dst, unsigned int count) { do *dst++ = *src++; while (--count != 0); }

ARM GAS /var/tmp//cc6fhgqr.s page 1

1 .file "copy.c" 2 .text 3 .align 2 4 .global copy 5 .type copy, %function 6 copy: 10 @ lr needed for prologue 11 .L2: 12 0000 0130D0E4 ldrb r3, [r0], #1 13 0004 012052E2 subs r2, r2, #1 14 0008 0130C1E4 strb r3, [r1], #1 15 000c FEFFFF1A bne .L2 16 0010 0EF0A0E1 mov pc, lr 17 .size copy, .-copy 18 .ident "GCC: (GNU) 3.4.3"
--
I just wonder what an assembly language programmer could
do better here - with or without a goto.
 Click to see the full signature
Reply to
Tauno Voipio

That's a bit strong isn't it? The example was purely describing the use of goto and showing that it doesn't have to obfuscate the code. I would guess that over 50% of professional programmers use that shorthand?????

Writing code is like writing a letter, there is no correct way to write it and everybody has their own styles, as long as it is easily readable, functional and efficient.

Reply to
EggNChips

As I'm sure you would agree, "easier to read" is a very subjective thing. As I have said in another post, writing code is like writing a letter, everyone has their own style and as long as it is easy to read, functional and efficient, then write it how you like.

IMO goto's aren't the incarnate of evil and if the programmer feels appropriate they can be used effectively. I generally never use more than one in a function, I have also seen code with excessive goto's and it's not pleasant.

Reply to
EggNChips

EggNChips scrobe on the papyrus:

The point I was making was just that. Because of the 'goto' the rest of the code was obfuscated and too complex.

Unfortunately, your example was none of those.

--
John B
Reply to
John B

If you think that's obfuscated and complex then you suck as a programmer :-)

see above :-)

Reply to
EggNChips

EggNChips scrobe on the papyrus:

. .

. .

Suck, blow ... it's all the same to me. I've been writing 'C' since

1979 and I bet you weren't even born then.
--
John B
Reply to
John B

In those days both C and Pascal were just toy languages :-).

OK, I rewrote a Pascal run time library for a specific platform (with a hardware floating point processor) in the late 1970's just to show that such languages could be used for some serious scientific work.

Before that, Fortran IV was used, with only the DO-loop and the GOTO statement as the only control structures. Even with Fortran IV, you can write quite readable code by using GOTOs only for forward jumps and use the DO loops for repetitions (even if that might sound a bit artificial).

Using C/Pascal style structured languages greatly reduces the need for gotos, but they do not eliminate it completely. I use it 0-3 times in each source file without being ashamed.

There seems to be horror stories about Basic destroying your brain or about GOTOs creating huge spaghetti nests, but the only real spaghetti code nests I have seen in real production code were related to Cobol PERFORM statements, in which restructuring might have helped.

Paul

Reply to
Paul Keinanen

"CBFalconer" schreef in bericht news: snipped-for-privacy@yahoo.com...

So am I. For backward jumps as well. Sometimes it is just too much hassle to wrap everything in if/then/elses. Fairly rare, yes, like 'continue' which I use even less but probably should consider to use more often.

Use what is available and practical.

--
Thanks, Frank.
(remove 'q' and '.invalid' when replying by email)
Reply to
Frank Bemelman

My principle use of continue is as a marker for empty statements, as in:

while ((EOF != (ch =getchar())) && (ch != '\n')) continue;

It stands out much better than a nude semicolon.

--
"If you want to post a followup via groups.google.com, don't use
 the broken "Reply" link at the bottom of the article.  Click on 
 Click to see the full signature
Reply to
CBFalconer

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.