Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #55792 > unrolled thread
| Started by | "S.K.R. de Jong" <SKRdJ@nowhere.net> |
|---|---|
| First post | 2015-01-04 00:46 +0000 |
| Last post | 2015-01-08 12:03 -0500 |
| Articles | 20 on this page of 102 — 30 participants |
Back to article view | Back to comp.lang.c
Is this poor style? "S.K.R. de Jong" <SKRdJ@nowhere.net> - 2015-01-04 00:46 +0000
Re: Is this poor style? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-01-03 16:58 -0800
Re: Is this poor style? Ian Collins <ian-news@hotmail.com> - 2015-01-04 20:37 +1300
Re: Is this poor style? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-01-04 02:32 -0800
Re: Is this poor style? Ian Collins <ian-news@hotmail.com> - 2015-01-05 09:39 +1300
Re: Is this poor style? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-01-04 22:53 +0000
Re: Is this poor style? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-01-04 01:29 +0000
Re: Is this poor style? Morris Dovey <mrdovey@iedu.com> - 2015-01-04 00:00 -0600
Re: Is this poor style? Morris Dovey <mrdovey@iedu.com> - 2015-01-04 02:20 -0600
Re: Is this poor style? August Karlstrom <fusionfile@gmail.com> - 2015-01-04 15:46 +0100
Re: Is this poor style? Ike Naar <ike@iceland.freeshell.org> - 2015-01-04 15:10 +0000
Re: Is this poor style? August Karlstrom <fusionfile@gmail.com> - 2015-01-04 17:06 +0100
Re: Is this poor style? Clark Smith <noaddress@nowhere.net> - 2015-01-04 15:30 +0000
Re: Is this poor style? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-01-04 07:44 -0800
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-05 00:35 +0000
Re: Is this poor style? BartC <bc@freeuk.com> - 2015-01-05 01:02 +0000
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-05 01:43 +0000
Re: Is this poor style? BartC <bc@freeuk.com> - 2015-01-05 11:35 +0000
Re: Is this poor style? raltbos@xs4all.nl (Richard Bos) - 2015-01-05 12:58 +0000
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-05 13:14 +0000
Re: Is this poor style? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-01-05 22:02 +0000
Re: Is this poor style? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-01-05 14:24 -0800
Re: Is this poor style? Ian Collins <ian-news@hotmail.com> - 2015-01-06 12:26 +1300
Re: Is this poor style? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-01-06 02:40 -0800
Re: Is this poor style? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-01-07 19:32 +0000
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-07 20:03 +0000
Re: Is this poor style? BartC <bc@freeuk.com> - 2015-01-07 20:27 +0000
Re: Is this poor style? Ian Collins <ian-news@hotmail.com> - 2015-01-08 09:55 +1300
Re: Is this poor style? Les Cargill <lcargill99@comcast.com> - 2015-01-07 18:13 -0600
Re: Is this poor style? Ian Collins <ian-news@hotmail.com> - 2015-01-08 13:17 +1300
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-07 21:02 +0000
Re: Is this poor style? Rosario193 <Rosario@invalid.invalid> - 2015-01-08 11:22 +0100
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-08 11:33 +0000
Re: Is this poor style? Rosario193 <Rosario@invalid.invalid> - 2015-01-08 13:08 +0100
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-08 12:54 +0000
Re: Is this poor style? David Brown <david.brown@hesbynett.no> - 2015-01-08 14:04 +0100
Re: Is this poor style? Keith Thompson <kst-u@mib.org> - 2015-01-07 13:57 -0800
Re: Is this poor style? Les Cargill <lcargill99@comcast.com> - 2015-01-07 18:12 -0600
Re: Is this poor style? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-01-07 20:56 +0000
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-07 21:18 +0000
Re: Is this poor style? glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-01-07 21:28 +0000
Re: Is this poor style? BartC <bc@freeuk.com> - 2015-01-06 11:28 +0000
Re: Is this poor style? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-01-07 20:19 +0000
Re: Is this poor style? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-01-07 16:05 -0800
Re: Is this poor style? glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-01-08 08:29 +0000
Re: Is this poor style? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-01-12 22:08 +0000
Re: Is this poor style? Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-24 20:35 -0700
Re: Is this poor style? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-03-25 08:43 -0700
Re: Is this poor style? Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-25 16:38 -0700
Re: Is this poor style? Stephen Sprunk <stephen@sprunk.org> - 2015-03-26 15:43 -0500
Re: Is this poor style? Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-28 08:57 -0700
Re: Is this poor style? Ian Collins <ian-news@hotmail.com> - 2015-01-08 13:23 +1300
Re: Is this poor style? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-01-07 16:53 -0800
Re: Is this poor style? Ian Collins <ian-news@hotmail.com> - 2015-01-08 14:11 +1300
Re: Is this poor style? Ian Collins <ian-news@hotmail.com> - 2015-01-08 11:10 +1300
Re: Is this poor style? John Bode <jfbode1029@gmail.com> - 2015-01-05 15:54 -0800
Re: Is this poor style? Rosario193 <Rosario@invalid.invalid> - 2015-01-06 11:03 +0100
Re: Is this poor style? Rosario193 <Rosario@invalid.invalid> - 2015-01-06 11:10 +0100
Re: Is this poor style? John Bode <jfbode1029@gmail.com> - 2015-01-06 06:03 -0800
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-06 14:44 +0000
Re: Is this poor style? "Osmium" <r124c4u102@comcast.net> - 2015-01-06 09:10 -0600
Re: Is this poor style? Rosario193 <Rosario@invalid.invalid> - 2015-01-08 11:14 +0100
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-08 11:31 +0000
Re: Is this poor style? Rosario193 <Rosario@invalid.invalid> - 2015-01-08 13:06 +0100
Re: Is this poor style? Rosario193 <Rosario@invalid.invalid> - 2015-01-08 13:19 +0100
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-08 12:53 +0000
Re: Is this poor style? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-01-08 05:49 -0800
Re: Is this poor style? Keith Thompson <kst-u@mib.org> - 2015-01-08 08:18 -0800
Re: Is this poor style? Rosario193 <Rosario@invalid.invalid> - 2015-01-09 07:58 +0100
Re: Is this poor style? Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-24 09:28 -0700
Re: Is this poor style? Keith Thompson <kst-u@mib.org> - 2015-03-24 13:57 -0700
Re: Is this poor style? Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-25 08:28 -0700
Re: Is this poor style? Keith Thompson <kst-u@mib.org> - 2015-03-25 12:17 -0700
Re: Is this poor style? Öö Tiib <ootiib@hot.ee> - 2015-04-05 17:03 -0700
Re: Is this poor style? John Bode <jfbode1029@gmail.com> - 2015-01-14 11:25 -0800
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-14 19:41 +0000
Re: Is this poor style? Rosario193 <Rosario@invalid.invalid> - 2015-01-15 09:01 +0100
Re: Is this poor style? Rosario193 <Rosario@invalid.invalid> - 2015-01-15 09:35 +0100
Re: Is this poor style? James Kuyper <jameskuyper@verizon.net> - 2015-01-04 11:15 -0500
Re: Is this poor style? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-01-04 21:38 +0000
Re: Is this poor style? Dr Nick <nospam-4@temporary-address.org.uk> - 2015-01-05 07:27 +0000
Re: Is this poor style? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-01-05 06:33 -0800
Re: Is this poor style? Vincenzo Mercuri <nomail@yahoo.it> - 2015-01-04 18:56 +0100
Re: Is this poor style? rouben@shady.(none) (Rouben Rostamian) - 2015-01-04 18:22 +0000
Re: Is this poor style? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-01-04 21:35 +0000
Re: Is this poor style? Ian Collins <ian-news@hotmail.com> - 2015-01-05 10:46 +1300
Re: Is this poor style? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-01-04 15:36 -0800
Re: Is this poor style? asetofsymbols@gmail.com - 2015-01-05 12:05 -0800
Re: Is this poor style? asetofsymbols@gmail.com - 2015-01-05 14:18 -0800
Re: Is this poor style? asetofsymbols@gmail.com - 2015-01-05 14:32 -0800
Re: Is this poor style? asetofsymbols@gmail.com - 2015-01-05 14:37 -0800
Re: Is this poor style? James Kuyper <jameskuyper@verizon.net> - 2015-01-05 18:23 -0500
Re: Is this poor style? Richard Heathfield <invalid@see.sig.invalid> - 2015-01-05 23:32 +0000
Re: Is this poor style? Keith Thompson <kst-u@mib.org> - 2015-01-05 15:31 -0800
Re: Is this poor style? Phil Carmody <pc+usenet@asdf.org> - 2015-01-13 15:00 +0200
Re: Is this poor style? Les Cargill <lcargill99@comcast.com> - 2015-01-04 15:07 -0600
Re: Is this poor style? jadill33@gmail.com - 2015-01-05 15:03 -0800
Re: Is this poor style? buja <buja66@gmail.com> - 2015-01-06 21:48 +0100
Re: Is this poor style? Rosario193 <Rosario@invalid.invalid> - 2015-01-08 11:21 +0100
Re: Is this poor style? buja <buja66@gmail.com> - 2015-01-08 12:42 +0100
Re: Is this poor style? "S.K.R. de Jong" <SKRdJ@nowhere.net> - 2015-01-08 15:29 +0000
Re: Is this poor style? James Kuyper <jameskuyper@verizon.net> - 2015-01-08 12:03 -0500
Page 3 of 6 — ← Prev page 1 2 [3] 4 5 6 Next page →
| From | glen herrmannsfeldt <gah@ugcs.caltech.edu> |
|---|---|
| Date | 2015-01-07 21:28 +0000 |
| Message-ID | <m8k8dd$4qo$1@speranza.aioe.org> |
| In reply to | #56016 |
Richard Heathfield <invalid@see.sig.invalid> wrote: > Jorgen Grahn wrote: (snip) >> The idea that every function should be "library-quality" may be one >> reason people write few, big and ugly functions. (Although a more >> important psychological reason probably is "but function calls are >> inefficient ... !"). > This is an astoundingly persistent meme. It's on a par with malloc > being costly. On a (relatively) recent collaboration with a > Canadian university, I asked the Good Professor (who will remain > firmly nameless, to protect the guilty) if it would not be better > to allow the problem size to be defined at runtime rather than at > compile time. (It was an NP problem for which we very much needed > a "good enough" solution *right the heck now* rather than a perfect > solution some time next millennium, so we were using GAs in an > attempt to short-cut our way to fame and glory.) He said that he > couldn't do that because it would take too much time to do the > allocation dynamically. Fortunately, he was open to persuasion. > As it turned out, the dynamic allocation - even for seriously > pathological cases - was blitzingly fast, of course. In a program > whose runtime budget was an hour or so, it took a tiny handful > of milliseconds. Dynamic allocation is slow if you do too much of it. In most cases, that means avoiding it in the inner loop. In your case, it sounds like you allocated once, outside all loops. That should be fast. > Function calls are, as you clearly understand, most definitely > *not* the bottleneck either. To my way of thinking, if you can > do X a brazillion times a second, X does not have a performance > problem. What's more, large, butt- ugly functions are far *less* > efficient, because they take too long for maintenance programmers > to grok. Obviously, a plethora of tiny weeny functions isn't going > to help either, because it takes too long to understand how they > all fit together. It's a trade-off, a balance. Again, you might avoid them in the innermost loop if you really need to be fast. It does seem that as computers have gotten faster, there has been even more work to speed up function calls. > It is impossible (well, all right, it's possible, but unwise) > to generalise on just how big a function can be before it needs > re-factoring. Some enormous functions are extraordinarily simple > and can be left in one piece (for example, S-boxes), and it is > easy to imagine how quite a small function might still be > too complex and could perhaps benefit from being broken into even > smaller functions. Yes it is hard to generalize, and it might even depend on how many times it is called. -- glen
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2015-01-06 11:28 +0000 |
| Message-ID | <sFPqw.487139$7A5.252993@fx17.am4> |
| In reply to | #55958 |
On 05/01/2015 22:02, Jorgen Grahn wrote: > On Mon, 2015-01-05, BartC wrote: >> On 05/01/2015 00:35, Richard Heathfield wrote: > ... >>> Whilst it is certainly true that I've heard that goto isn't good, I actually >>> have personal experience of its not being good. >> >> You might, nevertheless, prefer reading other people's code that uses >> gotos sensibly and consistently, to alternates that involve tortuous >> logic or where the action keep shifting to dozens of extra functions >> (with the complicated interfaces required to allow them to share common >> data). > > I think I was the one who mentioned using functional decomposition > instead of goto. I can assure you, that doesn't end up as "dozens of > extra functions", "complicated interfaces" or shared common data. Could you take any function, and turn any block of block within it into a second function? Could you do that several times to create several new functions? I would have these problems: (1) I would need to think of meaningful names for these function, ones that are unique because now I'm in the global name-space. (2) I would need to decide where to place those functions. Perhaps the original function was part of nice, tidy cluster with related functionality, but it's not going to be tidy much longer! (3) I'd need to document the functions and explain why each is only called from one place. Also what it actually does which is harder because it might not be meaningful outside its original context (4) I'd have to document the new calls in the original function. (5) If the blocks of code made use of local variables (using or setting their values) then this is where the interface between the original function and the new splinter functions can get awkward (not to mention inefficient unless inlined. But relying on inlining a function you went to all that trouble to 'out-line' seems perverse!). (6) If the code is under development, this gets more hairy if it now involves statements being moved across functions. (Imagine trying to reorganise your bookshelves but half your books are now with your neighbours.) (7) If I want to move the entire function, I now have all these extra dependencies. And any tools that lists all the functions is going to cluttered with all these new functions with ill-defined roles. In short, creating all this mess for the sake of a avoiding gotos is crazy. (There are ways of encapsulating blocks of code but keeping them within the function, such as local functions or something like the 'flow blocks' that Rick was on about, but those are not standard.) -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Jorgen Grahn <grahn+nntp@snipabacken.se> |
|---|---|
| Date | 2015-01-07 20:19 +0000 |
| Message-ID | <slrnmar573.4et.grahn+nntp@frailea.sa.invalid> |
| In reply to | #55981 |
On Tue, 2015-01-06, BartC wrote:
> On 05/01/2015 22:02, Jorgen Grahn wrote:
>> On Mon, 2015-01-05, BartC wrote:
>>> On 05/01/2015 00:35, Richard Heathfield wrote:
>> ...
>>>> Whilst it is certainly true that I've heard that goto isn't good, I actually
>>>> have personal experience of its not being good.
>>>
>>> You might, nevertheless, prefer reading other people's code that uses
>>> gotos sensibly and consistently, to alternates that involve tortuous
>>> logic or where the action keep shifting to dozens of extra functions
>>> (with the complicated interfaces required to allow them to share common
>>> data).
>>
>> I think I was the one who mentioned using functional decomposition
>> instead of goto. I can assure you, that doesn't end up as "dozens of
>> extra functions", "complicated interfaces" or shared common data.
>
> Could you take any function, and turn any block of block within it into
> a second function? Could you do that several times to create several new
> functions?
Yes, but that would suck. You sometimes see people do that: take a
big function, aim roughly and split it into two or three equal-sizes
parts. The result: smaller functions, but even worse code!
So that's not at all what I'm arguing for. I probably should explain
what I /really/ mean, but I find it difficult.
An example will have to do: a hexdump routine I use in many places. I
split it three times ... dump() being split out mostly to keep the
user interface types (void*) away from the logic. You could say that
the interface to hexdump() is a fourth split -- I expect the caller to
loop until the input is consumed.
Note that I only document the public function in this case -- there's
not a lot more that needs to be said.
static char nybble(uint8_t n)
{
if(n<10) return '0' + n;
return 'a' + (n-10);
}
static const uint8_t* dump(char* buf, size_t size,
const uint8_t* const begin,
const uint8_t* const end)
{
const uint8_t* p = begin;
if(size>2 && p!=end) {
*buf++ = nybble((*p) >> 4);
*buf++ = nybble((*p) & 0x0f);
size -= 2;
p++;
}
while(size>3 && p!=end) {
*buf++ = ' ';
*buf++ = nybble((*p) >> 4);
*buf++ = nybble((*p) & 0x0f);
size -= 3;
p++;
}
*buf++ = '\0';
return p;
}
/**
* Format [begin .. end) as hex octets, as much of it
* which fits in 'buf', of size 'size'. 'size' must
* allow room for the '\0' terminator (for example, be
* non-zero).
*
* Returns the first octet not formatted.
*
* This way, you can e.g. specify a buffer of 3*8 characters,
* loop until hexdump() returns 'end', printing the buffer + '\n'
* at every iteration -- and you have a hexdump with 8 octets
* per line.
*
*/
const void* hexdump(char* buf, size_t size,
const void* begin, const void* end)
{
return dump(buf, size, begin, end);
}
I have better examples -- where pages of messy code boiled down to
almost nothing, and boring bookkeeping became separated from the
"business logic" -- but that's code I wrote at work.
> I would have these problems:
We meant different things, but I still have some comments.
> (1) I would need to think of meaningful names for these function, ones
> that are unique because now I'm in the global name-space.
Unless the public function is defined inline in a header, they will be
static, so it's not too bad.
> (2) I would need to decide where to place those functions. Perhaps the
> original function was part of nice, tidy cluster with related
> functionality, but it's not going to be tidy much longer!
Right before their first use is my rule. I don't think of the result
as worse than a series of too-complex functions.
If corporate coding standards say you must place all of your static
functions at the top or bottom of the file -- then I give up and go
for too-complex functions instead. You can't navigate a ghetto of
random helper functions: they won't make sense outside their context,
and the context is the one or two functions which use them.
> (3) I'd need to document the functions and explain why each is only
> called from one place. Also what it actually does which is harder
> because it might not be meaningful outside its original context
Solution: keep it in its original context.
> (4) I'd have to document the new calls in the original function.
If you document at that detailed level, I guess you had to document
the code replaced by the call as well?
> (5) If the blocks of code made use of local variables (using or setting
> their values) then this is where the interface between the original
> function and the new splinter functions can get awkward
Yeah, you cannot split in a such a way that you're splitting "across"
a lot of variables. I'm not saying it's always easy to avoid. This
way of improving code by splitting things out isn't a silver bullet in
any way. It's just a tool, and quite often I find I cannot apply it.
> (not to mention
> inefficient unless inlined. But relying on inlining a function you went
> to all that trouble to 'out-line' seems perverse!).
Don't understand what you're saying here: I assume that when I write a
static function, my compiler will inline as it sees fit.
> (6) If the code is under development, this gets more hairy if it now
> involves statements being moved across functions. (Imagine trying to
> reorganise your bookshelves but half your books are now with your
> neighbours.)
>
> (7) If I want to move the entire function, I now have all these extra
> dependencies.
You just move it, together with the helper functions.
> And any tools that lists all the functions is going to
> cluttered with all these new functions with ill-defined roles.
You'll need better tools, then: tools that can highlight a translation
unit's public functions and downplay the static ones.
> In short, creating all this mess for the sake of a avoiding gotos is
> crazy.
That's not the main reason I do it -- I just noted that IME doing it
seems to also help the error handling logic.
> (There are ways of encapsulating blocks of code but keeping them
> within the function, such as local functions or something like the 'flow
> blocks' that Rick was on about, but those are not standard.)
/Jorgen
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.mclean5@btinternet.com> |
|---|---|
| Date | 2015-01-07 16:05 -0800 |
| Message-ID | <265c9e8c-9af4-4bbc-82e9-0801d11ad853@googlegroups.com> |
| In reply to | #56018 |
On Wednesday, January 7, 2015 8:19:58 PM UTC, Jorgen Grahn wrote:
> On Tue, 2015-01-06, BartC wrote:
> > On 05/01/2015 22:02, Jorgen Grahn wrote:
> >> On Mon, 2015-01-05, BartC wrote:
> >>> On 05/01/2015 00:35, Richard Heathfield wrote:
> >> ...
> >>>> Whilst it is certainly true that I've heard that goto isn't good, I actually
> >>>> have personal experience of its not being good.
> >>>
> >>> You might, nevertheless, prefer reading other people's code that uses
> >>> gotos sensibly and consistently, to alternates that involve tortuous
> >>> logic or where the action keep shifting to dozens of extra functions
> >>> (with the complicated interfaces required to allow them to share common
> >>> data).
> >>
> >> I think I was the one who mentioned using functional decomposition
> >> instead of goto. I can assure you, that doesn't end up as "dozens of
> >> extra functions", "complicated interfaces" or shared common data.
> >
> > Could you take any function, and turn any block of block within it into
> > a second function? Could you do that several times to create several new
> > functions?
>
> Yes, but that would suck. You sometimes see people do that: take a
> big function, aim roughly and split it into two or three equal-sizes
> parts. The result: smaller functions, but even worse code!
>
> So that's not at all what I'm arguing for. I probably should explain
> what I /really/ mean, but I find it difficult.
>
> An example will have to do: a hexdump routine I use in many places. I
> split it three times ... dump() being split out mostly to keep the
> user interface types (void*) away from the logic. You could say that
> the interface to hexdump() is a fourth split -- I expect the caller to
> loop until the input is consumed.
>
> Note that I only document the public function in this case -- there's
> not a lot more that needs to be said.
>
>
> static char nybble(uint8_t n)
> {
> if(n<10) return '0' + n;
> return 'a' + (n-10);
> }
>
> static const uint8_t* dump(char* buf, size_t size,
> const uint8_t* const begin,
> const uint8_t* const end)
> {
> const uint8_t* p = begin;
>
> if(size>2 && p!=end) {
> *buf++ = nybble((*p) >> 4);
> *buf++ = nybble((*p) & 0x0f);
> size -= 2;
> p++;
> }
> while(size>3 && p!=end) {
> *buf++ = ' ';
> *buf++ = nybble((*p) >> 4);
> *buf++ = nybble((*p) & 0x0f);
> size -= 3;
> p++;
> }
> *buf++ = '\0';
> return p;
> }
>
> /**
> * Format [begin .. end) as hex octets, as much of it
> * which fits in 'buf', of size 'size'. 'size' must
> * allow room for the '\0' terminator (for example, be
> * non-zero).
> *
> * Returns the first octet not formatted.
> *
> * This way, you can e.g. specify a buffer of 3*8 characters,
> * loop until hexdump() returns 'end', printing the buffer + '\n'
> * at every iteration -- and you have a hexdump with 8 octets
> * per line.
> *
> */
> const void* hexdump(char* buf, size_t size,
> const void* begin, const void* end)
> {
> return dump(buf, size, begin, end);
> }
>
>
> I have better examples -- where pages of messy code boiled down to
> almost nothing, and boring bookkeeping became separated from the
> "business logic" -- but that's code I wrote at work.
>
Here's a one-function version.
It's partly a matter of taste. But the one function version can be
snipped and pasted into a file being debugged more easily.
const void *hexdump2(char *buf, int size, const void *begin, const void *end)
{
const unsigned char *ptr = begin;
static char *hexdigits = "0123456789abcdef";
int N = 0;
if (size <= 0 || ptr == end)
return ptr;
while (1)
{
if (N >= size - 2)
break;
buf[N++] = hexdigits[(*ptr >> 4) & 0x0F];
if (N >= size - 1)
break;
buf[N++] = hexdigits[*ptr & 0x0F];
ptr++;
if (ptr == end)
break;
if (N >= size - 3)
break;
buf[N++] = ' ';
}
buf[N++] = 0;
return ptr;
}
[toc] | [prev] | [next] | [standalone]
| From | glen herrmannsfeldt <gah@ugcs.caltech.edu> |
|---|---|
| Date | 2015-01-08 08:29 +0000 |
| Message-ID | <m8lf5m$a9c$2@speranza.aioe.org> |
| In reply to | #56032 |
(snip, someone wrote) >> I have better examples -- where pages of messy code boiled down to >> almost nothing, and boring bookkeeping became separated from the >> "business logic" -- but that's code I wrote at work. I have seen some strange code when people were paid by the lines of code written. -- glen
[toc] | [prev] | [next] | [standalone]
| From | Jorgen Grahn <grahn+nntp@snipabacken.se> |
|---|---|
| Date | 2015-01-12 22:08 +0000 |
| Message-ID | <slrnmb8hf6.4et.grahn+nntp@frailea.sa.invalid> |
| In reply to | #56032 |
On Thu, 2015-01-08, Malcolm McLean wrote:
> On Wednesday, January 7, 2015 8:19:58 PM UTC, Jorgen Grahn wrote:
...
>> An example will have to do: a hexdump routine I use in many places. I
>> split it three times ... dump() being split out mostly to keep the
>> user interface types (void*) away from the logic. You could say that
>> the interface to hexdump() is a fourth split -- I expect the caller to
>> loop until the input is consumed.
>>
>> Note that I only document the public function in this case -- there's
>> not a lot more that needs to be said.
...
> Here's a one-function version.
>
> It's partly a matter of taste. But the one function version can be
> snipped and pasted into a file being debugged more easily.
>
> const void *hexdump2(char *buf, int size, const void *begin, const void *end)
> {
> const unsigned char *ptr = begin;
> static char *hexdigits = "0123456789abcdef";
> int N = 0;
>
> if (size <= 0 || ptr == end)
> return ptr;
>
> while (1)
> {
> if (N >= size - 2)
> break;
> buf[N++] = hexdigits[(*ptr >> 4) & 0x0F];
> if (N >= size - 1)
> break;
> buf[N++] = hexdigits[*ptr & 0x0F];
> ptr++;
> if (ptr == end)
> break;
> if (N >= size - 3)
> break;
> buf[N++] = ' ';
> }
> buf[N++] = 0;
> return ptr;
> }
I haven't read it in detail, but it seems like an improvement on my
version. I'm pleasantly surprised that void* versus const unsigned
char* wasn't a real problem (didn't affect readability) after all.
The fact that it's only one self-contained function isn't a plus from
my point of view, though: if I want such a function, I'll copy
hexdump.c and hexdump.h and link with them. Less of a hassle than
copy & pasting just a function IMO.
/Jorgen
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-03-24 20:35 -0700 |
| Message-ID | <kfnmw31eolx.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #56185 |
Jorgen Grahn <grahn+nntp@snipabacken.se> writes:
> On Thu, 2015-01-08, Malcolm McLean wrote:
>> On Wednesday, January 7, 2015 8:19:58 PM UTC, Jorgen Grahn wrote:
>
> ...
>
>>> An example will have to do: a hexdump routine I use in many
>>> places. I split it three times ... dump() being split out mostly
>>> to keep the user interface types (void*) away from the logic. You
>>> could say that the interface to hexdump() is a fourth split -- I
>>> expect the caller to loop until the input is consumed.
>>>
>>> Note that I only document the public function in this case --
>>> there's not a lot more that needs to be said.
>
> ...
>
>> Here's a one-function version. [snip]
>>
>> const void *hexdump2(char *buf, int size, const void *begin, const void *end)
>> {
>> const unsigned char *ptr = begin;
>> static char *hexdigits = "0123456789abcdef";
>> int N = 0;
>>
>> if (size <= 0 || ptr == end)
>> return ptr;
>>
>> while (1)
>> {
>> if (N >= size - 2)
>> break;
>> buf[N++] = hexdigits[(*ptr >> 4) & 0x0F];
>> if (N >= size - 1)
>> break;
>> buf[N++] = hexdigits[*ptr & 0x0F];
>> ptr++;
>> if (ptr == end)
>> break;
>> if (N >= size - 3)
>> break;
>> buf[N++] = ' ';
>> }
>> buf[N++] = 0;
>> return ptr;
>> }
>
> I haven't read it in detail, but it seems like an improvement on
> my version. I'm pleasantly surprised that void* versus const
> unsigned char* wasn't a real problem (didn't affect readability)
> after all. [snip unrelated]
For what you want to do I think having a single function produces
a better result (I tried several other formulations). The
definition above though is longer and more complicated than it
needs to be. The example below retains the interface and semantics
of the original, not counting the reliance there on alphabetic
characters being contiguous, the unstated reliance here on
CHAR_BIT == 8, and the added 'restrict' qualifiers which
presumably also could apply to the original:
const void*
hexdump( char *restrict p, size_t size, const void* begin, const void* end ){
static char hex[] = "0123456789abcdef";
const unsigned char *restrict q = begin;
size_t k = ((char*)end - (char*)begin) * 3;
for( size_t n = k < size ? k : size; n > 2; q++, n -= 3 ){
*p++ = hex[ *q / 16 ];
*p++ = hex[ *q % 16 ];
if( n > 5 ) *p++ = ' ';
}
*p = 0;
return q;
}
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.mclean5@btinternet.com> |
|---|---|
| Date | 2015-03-25 08:43 -0700 |
| Message-ID | <69396a4c-1349-45ac-a040-02565e9c9c93@googlegroups.com> |
| In reply to | #58890 |
On Wednesday, March 25, 2015 at 3:35:19 AM UTC, Tim Rentsch wrote:
>
> For what you want to do I think having a single function produces
> a better result (I tried several other formulations). The
> definition above though is longer and more complicated than it
> needs to be. The example below retains the interface and semantics
> of the original, not counting the reliance there on alphabetic
> characters being contiguous, the unstated reliance here on
> CHAR_BIT == 8, and the added 'restrict' qualifiers which
> presumably also could apply to the original:
>
> const void*
> hexdump( char *restrict p, size_t size, const void* begin, const void* end ){
> static char hex[] = "0123456789abcdef";
> const unsigned char *restrict q = begin;
> size_t k = ((char*)end - (char*)begin) * 3;
>
> for( size_t n = k < size ? k : size; n > 2; q++, n -= 3 ){
> *p++ = hex[ *q / 16 ];
> *p++ = hex[ *q % 16 ];
> if( n > 5 ) *p++ = ' ';
> }
>
> *p = 0;
> return q;
> }
>
>
I believe the restrict is superfluous, as a const-qualified pointer can be assumed not to
alias a non-const pointer.
It is a bit tighter-coded than mine, however.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-03-25 16:38 -0700 |
| Message-ID | <kfnsics8x6m.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #58918 |
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> On Wednesday, March 25, 2015 at 3:35:19 AM UTC, Tim Rentsch wrote:
>
>> For what you want to do I think having a single function produces
>> a better result (I tried several other formulations). The
>> definition above though is longer and more complicated than it
>> needs to be. The example below retains the interface and semantics
>> of the original, not counting the reliance there on alphabetic
>> characters being contiguous, the unstated reliance here on
>> CHAR_BIT == 8, and the added 'restrict' qualifiers which
>> presumably also could apply to the original:
>>
>> const void*
>> hexdump( char *restrict p, size_t size, const void* begin, const void* end ){
>> static char hex[] = "0123456789abcdef";
>> const unsigned char *restrict q = begin;
>> size_t k = ((char*)end - (char*)begin) * 3;
>>
>> for( size_t n = k < size ? k : size; n > 2; q++, n -= 3 ){
>> *p++ = hex[ *q / 16 ];
>> *p++ = hex[ *q % 16 ];
>> if( n > 5 ) *p++ = ' ';
>> }
>>
>> *p = 0;
>> return q;
>> }
>
> I believe the restrict is superfluous, as a const-qualified
> pointer can be assumed not to alias a non-const pointer.
No, that assumption is not safe in general. In fact I ran into a
case the other day very much like this one, where one pointed-to
type was const and the other wasn't, where adding 'restrict's
improved the code that was generated.
[toc] | [prev] | [next] | [standalone]
| From | Stephen Sprunk <stephen@sprunk.org> |
|---|---|
| Date | 2015-03-26 15:43 -0500 |
| Message-ID | <mf1r22$gc7$1@dont-email.me> |
| In reply to | #58918 |
On 25-Mar-15 10:43, Malcolm McLean wrote: > I believe the restrict is superfluous, as a const-qualified pointer > can be assumed not to alias a non-const pointer. It is a bit > tighter-coded than mine, however. Why would one assume that? char *p = malloc(1); const char *q = p; foo(p,q); AIUI, the usual assumption is that pointers to different base types won't alias, but qualifiers such as const aren't considered. S -- Stephen Sprunk "God does not play dice." --Albert Einstein CCIE #3723 "God is an inveterate gambler, and He throws the K5SSS dice at every possible opportunity." --Stephen Hawking
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-03-28 08:57 -0700 |
| Message-ID | <kfnk2y1867u.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #59041 |
Stephen Sprunk <stephen@sprunk.org> writes: > On 25-Mar-15 10:43, Malcolm McLean wrote: >> I believe the restrict is superfluous, as a const-qualified pointer >> can be assumed not to alias a non-const pointer. It is a bit >> tighter-coded than mine, however. > > Why would one assume that? > > char *p = malloc(1); > const char *q = p; > foo(p,q); > > AIUI, the usual assumption is that pointers to different base > types won't alias, That's mostly right (not counting character types), but there is an exception for the unsigned version of a signed integer type, and vice versa. > but qualifiers such as const aren't considered. Right; generally the presence of absence of qualifiers makes no difference. A note of caution, however - gcc has an option for 'strict aliasing', which AIUI actually is more restrictive about what types can alias than the C standard allows. That would mean that (some) programs that are legal and defined ISO C may exhibit non-conforming behavior if compiled using gcc's strict aliasing option.
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2015-01-08 13:23 +1300 |
| Message-ID | <ch6108FpgmlU10@mid.individual.net> |
| In reply to | #56018 |
Jorgen Grahn wrote:
>
> I have better examples -- where pages of messy code boiled down to
> almost nothing, and boring bookkeeping became separated from the
> "business logic" -- but that's code I wrote at work.
Some of the more common instances I see are switch statements with way
too much code for each case which cries out to be extracted. What's
easier to follow:
switch( bla )
{
case one:
// 30 lines of code
break;
case two:
// 40 lines of code
break;
case three:
// 30 lines of code
break;
etc
}
or
switch( bla )
{
case one:
process_one();
break;
case two:
process_two();
break;
case three:
process_three();
break;
etc
}
The second is often how I design a function, effectively turning
psudo-code (the functions calls) into real code.
--
Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.mclean5@btinternet.com> |
|---|---|
| Date | 2015-01-07 16:53 -0800 |
| Message-ID | <1660e7ed-5e31-423f-87b0-d3020c098863@googlegroups.com> |
| In reply to | #56037 |
On Thursday, January 8, 2015 12:23:46 AM UTC, Ian Collins wrote: > > Some of the more common instances I see are switch statements with way > too much code for each case which cries out to be extracted. What's > easier to follow: > A Windows callback is often like that. I usually break it up, so a paint message will call "paint me", a create will call a private constructor and set the user pointer to it, and so on. However a Windows callback isn't really a single function, it's lots of functions with different parameters artificially packaged into one.
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2015-01-08 14:11 +1300 |
| Message-ID | <ch63prFpgmjU1@mid.individual.net> |
| In reply to | #56038 |
Malcolm McLean wrote: > On Thursday, January 8, 2015 12:23:46 AM UTC, Ian Collins wrote: >> >> Some of the more common instances I see are switch statements with way >> too much code for each case which cries out to be extracted. What's >> easier to follow: >> > A Windows callback is often like that. > > I usually break it up, so a paint message will call "paint me", > a create will call a private constructor and set the user pointer to > it, and so on. > However a Windows callback isn't really a single function, it's lots > of functions with different parameters artificially packaged into one. Lots (maybe most?) functions with big switch statements fall into that category. The usually handle some form of protocol where the message type is the first byte or two, the rest specific messages. One I had to re-write recently was a single switch with over a thousand lines used to process Apple MFI protocol messages. -- Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2015-01-08 11:10 +1300 |
| Message-ID | <ch5p66FpgmlU8@mid.individual.net> |
| In reply to | #55981 |
BartC wrote: > On 05/01/2015 22:02, Jorgen Grahn wrote: >> On Mon, 2015-01-05, BartC wrote: >>> On 05/01/2015 00:35, Richard Heathfield wrote: >> ... >>>> Whilst it is certainly true that I've heard that goto isn't good, I actually >>>> have personal experience of its not being good. >>> >>> You might, nevertheless, prefer reading other people's code that uses >>> gotos sensibly and consistently, to alternates that involve tortuous >>> logic or where the action keep shifting to dozens of extra functions >>> (with the complicated interfaces required to allow them to share common >>> data). >> >> I think I was the one who mentioned using functional decomposition >> instead of goto. I can assure you, that doesn't end up as "dozens of >> extra functions", "complicated interfaces" or shared common data. > > Could you take any function, and turn any block of block within it into > a second function? Could you do that several times to create several new > functions? Yes, it is a common refactoring known as "extract method". > I would have these problems: > > (1) I would need to think of meaningful names for these function, ones > that are unique because now I'm in the global name-space. Not if they are static. If the block of code is doing something specific (which is why you are extracting it), choosing a name should be straightforward. > (2) I would need to decide where to place those functions. Perhaps the > original function was part of nice, tidy cluster with related > functionality, but it's not going to be tidy much longer! Indeed, it will be tidier once all the clutter is removed... > (3) I'd need to document the functions and explain why each is only > called from one place. Also what it actually does which is harder > because it might not be meaningful outside its original context Very often the cue to extract a function is the need to comment a block of code, so (if it is still required) the comment can go with it. Choosing a meaningful name for the function will often remove the need for the comment. Why would you have to explain why it is called from one place? > (4) I'd have to document the new calls in the original function. Why? Isn't calling them clear enough? > (5) If the blocks of code made use of local variables (using or setting > their values) then this is where the interface between the original > function and the new splinter functions can get awkward (not to mention > inefficient unless inlined. But relying on inlining a function you went > to all that trouble to 'out-line' seems perverse!). In that case there are a couple of options: 1) do nothing 2) if there aren't too many, pass the local variables as parameters 3) if there will be several functions working on the same data, consider using a struct. > (6) If the code is under development, this gets more hairy if it now > involves statements being moved across functions. (Imagine trying to > reorganise your bookshelves but half your books are now with your > neighbours.) Eh? If the code is under development, isn't it easier to test smaller chunks? > (7) If I want to move the entire function, I now have all these extra > dependencies. And any tools that lists all the functions is going to > cluttered with all these new functions with ill-defined roles. Surely the roles are well defined, which is why you extracted the functions in the first place. > In short, creating all this mess for the sake of a avoiding gotos is > crazy. (There are ways of encapsulating blocks of code but keeping them > within the function, such as local functions or something like the 'flow > blocks' that Rick was on about, but those are not standard.) More often than not functions are extracted to simplify and improve the code, not to avoid a goto. If you work with small functions from the beginning, you are far less likely to end up with a function the uses goto. -- Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | John Bode <jfbode1029@gmail.com> |
|---|---|
| Date | 2015-01-05 15:54 -0800 |
| Message-ID | <3702c3f1-6594-47ee-b30c-42604139d92d@googlegroups.com> |
| In reply to | #55859 |
On Sunday, January 4, 2015 6:35:13 PM UTC-6, Richard Heathfield wrote:
> Malcolm McLean wrote:
>
> > On Sunday, January 4, 2015 3:30:58 PM UTC, Clark Smith wrote:
> >>
> >> The idea is that some actions must be taken that must be correctly undone
> >> in case of error. With this approach, everything is centralized at the
> >> end of the loop.
> >>
> > That's basically sensible.
> >
> > Typically a function is constructing some complex data structure. If
> > it encounters an error, the structure is in a half-completed state,
> > so needs deconstructing with care to avoid memory leaks. So you want
> > the code in one place.
> >
> > However just use goto error_exit. Some people have heard that goto
> > isn't good. Whilst the person who made that statement (Dijkstra)
> > was no idiot, repeating him like a mantra isn't very helpful,
> > and requires no thought.
>
> Whilst it is certainly true that I've heard that goto isn't good, I actually
> have personal experience of its not being good. My first programming
> language was VS/BASIC. In 1982-83, I wrote several programs that, to my
> inexperienced eye, seemed to me to be very large - hundreds and hundreds of
> lines of code! These programs were littered with GOTO statements. (It didn't
> help that I didn't know about GOSUB.) On far too many occasions, I wanted to
> change the behaviour of a particular program in a particular way, only to
> find that I simply couldn't do it - the flow of control was just too...
> well, not to put too fine a point on it, too screwed-up.
>
BTDTGTFTS. I've told that story a couple of dozen times on this forum:
huge, monolithic main() function, gotos out the wazoo branching either
direction, literally several hundred distinct variables, etc. Slow, brittle
as hell. Told the customer we could either rewrite it from scratch or they
could buy faster hardware. They bought faster hardware.
This isn't that situation. He wants to bail out of a multi-step operation
that may fail at any point, and needs to back out anything that was done up
to that point. Lacking a structured exception handling mechanism, using a
goto is probably the least-painful option available.
if ( condition_a_fails )
goto error_handler;
if ( condition_b_fails )
goto error_handler;
...
error_handler:
if ( operation_a_run )
backout_operation_a;
if ( operation_b_run )
backout_operation_a;
backout_operation_b;
etc.
To the OP: if you feel like repeatedly stabbing yourself with a spork might
be fun, you could try C's excuse for an exception handling mechanism,
setjmp and longjmp. I took your toy example and rewrote it as follows:
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
int f( const char *x, int l )
{
char *a = NULL;
char *b = NULL;
enum error_type {OKAY, SOURCE_NULL, BAD_LENGTH, MALLOC_FAILED_A, MALLOC_FAILED_B} ;
jmp_buf TryBlock;
int diagnostic = 0;
enum error_type status = setjmp( TryBlock ); // "try:
if ( status != OKAY )
{
diagnostic = 1;
switch( status )
{
case SOURCE_NULL:
printf( "x is NULL!\n" );
break;
case BAD_LENGTH:
printf( "l is > 255!\n" );
break;
case MALLOC_FAILED_A:
printf( "Could not allocate memory for a!\n" );
break;
case MALLOC_FAILED_B:
printf( "Could not allocate memory for b!\n" );
printf( "Freeing allocated memory for a\n" );
free( a );
break;
default:
break;
}
}
else
{
if ( !x )
longjmp( TryBlock, SOURCE_NULL );
if ( l > 255 )
longjmp( TryBlock, BAD_LENGTH );
a = malloc( 256 );
if ( !a )
longjmp( TryBlock, MALLOC_FAILED_A );
b = malloc( 2*256 );
if ( !b )
longjmp( TryBlock, MALLOC_FAILED_B );
strcpy( a, x );
strcpy( b, x );
printf( "a = %s\n", a );
printf( "b = %s\n", b );
free( a );
free( b );
}
return diagnostic;
}
int main( void )
{
if ( f( "test", 5 ) )
printf( "test(\"test\", 5) failed with an exception\n" );
if ( f( NULL, 0 ) )
printf( "test(NULL, 0) failed with an exception\n" );
if ( f( "test", 257 ) )
printf( "test(\"test\", 257) failed with an exception\n" );
exit( 0 );
}
When run, it gives the output
a = test
b = test
x is NULL!
test(NULL, 0) failed with an exception
l is > 255!
test("test", 257) failed with an exception
If a condition fails, it bails immediately and executes the relevant
"exception" path. Not a goto in sight.
It's also pretty gagariffic code. I tossed this off in about 20 minutes, so
no doubt it could be structured a bit better, but it'd still be a mess.
Having to handle the exception cases *before* the "try" block is just
a bit counterintuitive.
[toc] | [prev] | [next] | [standalone]
| From | Rosario193 <Rosario@invalid.invalid> |
|---|---|
| Date | 2015-01-06 11:03 +0100 |
| Message-ID | <ifanaahc4ec5vn7lm7t12antr1ja0l7g9j@4ax.com> |
| In reply to | #55970 |
On Mon, 5 Jan 2015 15:54:34 -0800 (PST), John Bode wrote:
>On Sunday, January 4, 2015 6:35:13 PM UTC-6, Richard Heathfield wrote:
>> Malcolm McLean wrote:
>>
>> > On Sunday, January 4, 2015 3:30:58 PM UTC, Clark Smith wrote:
>> >>
>> >> The idea is that some actions must be taken that must be correctly undone
>> >> in case of error. With this approach, everything is centralized at the
>> >> end of the loop.
>> >>
>> > That's basically sensible.
>> >
>> > Typically a function is constructing some complex data structure. If
>> > it encounters an error, the structure is in a half-completed state,
>> > so needs deconstructing with care to avoid memory leaks. So you want
>> > the code in one place.
>> >
>> > However just use goto error_exit. Some people have heard that goto
>> > isn't good. Whilst the person who made that statement (Dijkstra)
>> > was no idiot, repeating him like a mantra isn't very helpful,
>> > and requires no thought.
>>
>> Whilst it is certainly true that I've heard that goto isn't good, I actually
>> have personal experience of its not being good. My first programming
>> language was VS/BASIC. In 1982-83, I wrote several programs that, to my
>> inexperienced eye, seemed to me to be very large - hundreds and hundreds of
>> lines of code! These programs were littered with GOTO statements. (It didn't
>> help that I didn't know about GOSUB.) On far too many occasions, I wanted to
>> change the behaviour of a particular program in a particular way, only to
>> find that I simply couldn't do it - the flow of control was just too...
>> well, not to put too fine a point on it, too screwed-up.
>>
>
>BTDTGTFTS. I've told that story a couple of dozen times on this forum:
>huge, monolithic main() function, gotos out the wazoo branching either
>direction, literally several hundred distinct variables, etc. Slow, brittle
>as hell. Told the customer we could either rewrite it from scratch or they
>could buy faster hardware. They bought faster hardware.
>
>This isn't that situation. He wants to bail out of a multi-step operation
>that may fail at any point, and needs to back out anything that was done up
>to that point. Lacking a structured exception handling mechanism, using a
>goto is probably the least-painful option available.
>
> if ( condition_a_fails )
> goto error_handler;
>
> if ( condition_b_fails )
> goto error_handler;
>
> ...
>
>error_handler:
> if ( operation_a_run )
> backout_operation_a;
>
> if ( operation_b_run )
> backout_operation_a;
> backout_operation_b;
>
>etc.
>
>To the OP: if you feel like repeatedly stabbing yourself with a spork might
>be fun, you could try C's excuse for an exception handling mechanism,
>setjmp and longjmp. I took your toy example and rewrote it as follows:
>
>#include <stdio.h>
>#include <setjmp.h>
>#include <stdlib.h>
>#include <string.h>
>
>int f( const char *x, int l )
>{
> char *a = NULL;
> char *b = NULL;
>
> enum error_type {OKAY, SOURCE_NULL, BAD_LENGTH, MALLOC_FAILED_A, MALLOC_FAILED_B} ;
> jmp_buf TryBlock;
> int diagnostic = 0;
> enum error_type status = setjmp( TryBlock ); // "try:
> if ( status != OKAY )
> {
> diagnostic = 1;
>
> switch( status )
> {
> case SOURCE_NULL:
> printf( "x is NULL!\n" );
> break;
>
> case BAD_LENGTH:
> printf( "l is > 255!\n" );
> break;
>
> case MALLOC_FAILED_A:
> printf( "Could not allocate memory for a!\n" );
> break;
>
> case MALLOC_FAILED_B:
> printf( "Could not allocate memory for b!\n" );
> printf( "Freeing allocated memory for a\n" );
> free( a );
> break;
>
> default:
> break;
> }
> }
> else
> {
> if ( !x )
> longjmp( TryBlock, SOURCE_NULL );
>
> if ( l > 255 )
> longjmp( TryBlock, BAD_LENGTH );
>
> a = malloc( 256 );
> if ( !a )
> longjmp( TryBlock, MALLOC_FAILED_A );
>
> b = malloc( 2*256 );
> if ( !b )
> longjmp( TryBlock, MALLOC_FAILED_B );
>
> strcpy( a, x );
> strcpy( b, x );
>
> printf( "a = %s\n", a );
> printf( "b = %s\n", b );
>
> free( a );
> free( b );
> }
>
> return diagnostic;
>}
>
>int main( void )
>{
> if ( f( "test", 5 ) )
> printf( "test(\"test\", 5) failed with an exception\n" );
> if ( f( NULL, 0 ) )
> printf( "test(NULL, 0) failed with an exception\n" );
> if ( f( "test", 257 ) )
> printf( "test(\"test\", 257) failed with an exception\n" );
> exit( 0 );
>}
>
>When run, it gives the output
>
>a = test
>b = test
>x is NULL!
>test(NULL, 0) failed with an exception
>l is > 255!
>test("test", 257) failed with an exception
>
>If a condition fails, it bails immediately and executes the relevant
>"exception" path. Not a goto in sight.
>
>It's also pretty gagariffic code. I tossed this off in about 20 minutes, so
>no doubt it could be structured a bit better, but it'd still be a mess.
>Having to handle the exception cases *before* the "try" block is just
>a bit counterintuitive.
if i would write one function as f() that does something...
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define G goto
#define P printf
#define u8 unsigned char
#define u32 unsigned int
/*
This function double cat the arg string x in res
return 0 for all ok
in the other case [error]
a pointer to a string that say what goes wrong
in the case all ok the caller has free what res point...
2 exit point one for error one for all ok
no exceptions use
*/
u8* catcat(u8** res, u8* x)
{u8 *a, *b, *c, *r;
u32 len;
r="Error Arg";
if(res==0) {ex: return r; }
*res=0;
if(x==0) G ex;
r="Error strlen";
len=strlen(x);
/* all has its limit all routine that not take in count limits are
wrong by design... */
// if(len>0x7FFFFF00) G ex;
if(len>0x7F) G ex;
r="Error malloc";
if((a=malloc(len+1))==0) G ex;
if((b=malloc(2*len+2))==0)
{ex1: free(a); G ex;}
strcpy(a, x);
strcpy(b, x);
strcpy(b+len, a);
free(a);
*res=b;
return 0;
}
int main(void)
{u8 *r, *res, big[1024];
u32 i;
if(r=catcat(&res, "test"))
P("catcat(\"test\") failed with error %s\n", r);
else P("Result catcat(\"test\")=%s\n", res);
if(res) free(res);
if(r=catcat(0, "test"))
P("catcat(0, \"test\") failed with error %s\n", r);
else P("Result catcat(\"test\")=%s\n", res);
if(res) free(res);
if(r=catcat(&res, 0 ))
P("catcat(0) failed with error %s\n", r);
else P("Result catcat(\"test\")=%s\n", res);
if(res) free(res);
for(i=0;i<1000; ++i)
big[i]='c';
big[i]=0;
if(r=catcat(&res, big ))
P("catcat(\"big\") failed with error %s\n", r);
else P("Result catcat(\"test\")=%s\n", res);
if(res) free(res);
return 0;
}
[toc] | [prev] | [next] | [standalone]
| From | Rosario193 <Rosario@invalid.invalid> |
|---|---|
| Date | 2015-01-06 11:10 +0100 |
| Message-ID | <72dnaa9g01gvu94n6j6bvp0qsm770j1vra@4ax.com> |
| In reply to | #55978 |
On Tue, 06 Jan 2015 11:03:34 +0100, Rosario193
<Rosario@invalid.invalid> wrote:
>#include <stdlib.h>
>#include <string.h>
>#include <stdio.h>
>#define G goto
>#define P printf
>#define u8 unsigned char
>#define u32 unsigned int
>
>/*
> This function double cat the arg string x in res
> return 0 for all ok
> in the other case [error]
> a pointer to a string that say what goes wrong
> in the case all ok the caller has free what res point...
>
> 2 exit point one for error one for all ok
> no exceptions use
>*/
>u8* catcat(u8** res, u8* x)
>{u8 *a, *b, *c, *r;
> u32 len;
>
> r="Error Arg";
> if(res==0) {ex: return r; }
> *res=0;
> if(x==0) G ex;
>
> r="Error strlen";
> len=strlen(x);
>
>/* all has its limit all routine that not take in count limits are
>wrong by design... */
> // if(len>0x7FFFFF00) G ex;
> if(len>0x7F) G ex;
>
> r="Error malloc";
> if((a=malloc(len+1))==0) G ex;
> if((b=malloc(2*len+2))==0)
> {ex1: free(a); G ex;}
>
> strcpy(a, x);
> strcpy(b, x);
> strcpy(b+len, a);
>
> free(a);
>
> *res=b;
> return 0;
>}
>
>
>int main(void)
>{u8 *r, *res, big[1024];
> u32 i;
>
> if(r=catcat(&res, "test"))
> P("catcat(\"test\") failed with error %s\n", r);
> else P("Result catcat(\"test\")=%s\n", res);
> if(res) free(res);
>
> if(r=catcat(0, "test"))
> P("catcat(0, \"test\") failed with error %s\n", r);
> else P("Result catcat(\"test\")=%s\n", res);
> if(res) free(res);
>
> if(r=catcat(&res, 0 ))
> P("catcat(0) failed with error %s\n", r);
> else P("Result catcat(\"test\")=%s\n", res);
> if(res) free(res);
>
> for(i=0;i<1000; ++i)
> big[i]='c';
> big[i]=0;
>
> if(r=catcat(&res, big ))
> P("catcat(\"big\") failed with error %s\n", r);
> else P("Result catcat(\"test\")=%s\n", res);
> if(res) free(res);
>
> return 0;
>}
Result catcat("test")=testtest
catcat(0, "test") failed with error Error Arg
catcat(0) failed with error Error Arg
catcat("big") failed with error Error strlen
[toc] | [prev] | [next] | [standalone]
| From | John Bode <jfbode1029@gmail.com> |
|---|---|
| Date | 2015-01-06 06:03 -0800 |
| Message-ID | <603b5f3b-908f-4b3b-99ca-511716c368ec@googlegroups.com> |
| In reply to | #55978 |
On Tuesday, January 6, 2015 4:03:46 AM UTC-6, Rosario193 wrote:
[snip]
>
> #include <stdlib.h>
> #include <string.h>
> #include <stdio.h>
> #define G goto
> #define P printf
> #define u8 unsigned char
> #define u32 unsigned int
>
*Please* don't do this. Please don't suggest anyone else do it either. Using
the preprocessor to redefine/create synonyms for keywords and types is bad
juju.
It does *not* improve readability, and in my experience creates maintenance
headaches down the line.
If you insist on aliases for type names, use typedef instead of the
preprocessor:
typedef unsigned char u8
typedef unsigned int u32
but before you do that, check to make sure that uint8_t and uint32_t aren't
already defined in stdint.h
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <invalid@see.sig.invalid> |
|---|---|
| Date | 2015-01-06 14:44 +0000 |
| Message-ID | <YwSqw.328173$Kl4.155860@fx01.am4> |
| In reply to | #55983 |
John Bode wrote: > On Tuesday, January 6, 2015 4:03:46 AM UTC-6, Rosario193 wrote: > [snip] >> >> #include <stdlib.h> >> #include <string.h> >> #include <stdio.h> >> #define G goto >> #define P printf >> #define u8 unsigned char >> #define u32 unsigned int >> > > *Please* don't do this. He's been doing this for about 15 years, despite closely reasoned arguments against it, repeated frequently. Realistically, do you really think he's suddenly going to develop some kind of cluefulness at this point? <snip> -- Richard Heathfield Email: rjh at cpax dot org dot uk "Usenet is a strange place" - dmr 29 July 1999 Sig line 4 vacant - apply within
[toc] | [prev] | [next] | [standalone]
Page 3 of 6 — ← Prev page 1 2 [3] 4 5 6 Next page →
Back to top | Article view | comp.lang.c
csiph-web