Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #176581 > unrolled thread
| Started by | Blue-Maned_Hawk <bluemanedhawk@invalid.invalid> |
|---|---|
| First post | 2023-09-27 22:52 +0000 |
| Last post | 2023-09-30 09:37 +0100 |
| Articles | 20 on this page of 62 — 12 participants |
Back to article view | Back to comp.lang.c
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Libraries using longjmp for error handling (was: Re: More on NNTP testing) Blue-Maned_Hawk <bluemanedhawk@invalid.invalid> - 2023-09-27 22:52 +0000
Re: Libraries using longjmp for error handling (was: Re: More on NNTP testing) Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2023-09-28 08:19 +0800
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-28 02:18 +0100
Re: Libraries using longjmp for error handling Blue-Maned_Hawk <bluemanedhawk@invalid.invalid> - 2023-09-28 22:30 +0000
Re: Libraries using longjmp for error handling scott@slp53.sl.home (Scott Lurndal) - 2023-09-28 22:33 +0000
Re: Libraries using longjmp for error handling Anton Shepelev <anton.txt@gmail.moc> - 2023-09-29 01:41 +0300
Re: Libraries using longjmp for error handling scott@slp53.sl.home (Scott Lurndal) - 2023-09-28 23:45 +0000
Re: Libraries using longjmp for error handling Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-09-28 17:35 -0700
Re: Libraries using longjmp for error handling David Brown <david.brown@hesbynett.no> - 2023-09-29 16:49 +0200
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-28 18:24 -0700
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-29 03:19 +0100
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-29 07:46 -0700
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-29 21:02 +0100
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-29 21:56 -0700
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-10-01 00:06 +0100
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-30 20:35 -0700
Re: Libraries using longjmp for error handling Anton Shepelev <anton.txt@gmail.moc> - 2023-10-01 14:44 +0300
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-10-01 15:45 +0100
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-10-01 09:28 -0700
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-10-01 20:49 +0100
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-10-02 02:31 -0700
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-10-02 23:55 +0100
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-10-03 05:01 -0700
Re: Libraries using longjmp for error handling Anton Shepelev <anton.txt@gmail.moc> - 2023-09-29 23:58 +0300
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-10-01 02:52 -0700
Re: Libraries using longjmp for error handling Anton Shepelev <anton.txt@gmail.moc> - 2023-10-01 14:33 +0300
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-28 01:48 +0100
Re: Libraries using longjmp for error handling (was: Re: More on NNTP testing) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-28 05:11 +0000
Re: Libraries using longjmp for error handling (was: Re: More on NNTP testing) Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-28 06:26 +0000
Re: Libraries using longjmp for error handling (was: Re: More on NNTP testing) Anton Shepelev <anton.txt@gmail.moc> - 2023-09-28 16:02 +0300
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-28 14:44 +0100
Re: Libraries using longjmp for error handling Anton Shepelev <anton.txt@gmail.moc> - 2023-09-28 18:31 +0300
Re: Libraries using longjmp for error handling Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-28 16:43 +0000
Re: Libraries using longjmp for error handling scott@slp53.sl.home (Scott Lurndal) - 2023-09-28 17:00 +0000
Re: Libraries using longjmp for error handling Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-28 17:16 +0000
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-28 19:38 +0100
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-28 16:05 -0700
Re: Libraries using longjmp for error handling Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-29 00:26 +0000
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-28 23:20 -0700
Re: Libraries using longjmp for error handling Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-09-28 18:31 -0700
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-29 03:24 +0100
Re: Libraries using longjmp for error handling Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-29 03:12 +0000
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-28 22:45 -0700
Re: Libraries using longjmp for error handling Spiros Bousbouras <spibou@gmail.com> - 2023-09-29 12:02 +0000
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-29 08:10 -0700
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-29 17:03 +0100
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-29 10:15 -0700
Re: Libraries using longjmp for error handling gazelle@shell.xmission.com (Kenny McCormack) - 2023-09-29 17:17 +0000
Re: Libraries using longjmp for error handling Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-29 18:53 +0000
Re: Libraries using longjmp for error handling Anton Shepelev <anton.txt@gmail.moc> - 2023-09-29 18:11 +0300
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-29 10:20 -0700
Re: Libraries using longjmp for error handling Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-09-29 11:30 -0700
Re: Libraries using longjmp for error handling Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-29 18:31 +0000
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-28 19:27 +0100
Re: Libraries using longjmp for error handling Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-28 20:24 +0000
Re: Libraries using longjmp for error handling Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-09-28 22:23 +0100
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-28 15:43 -0700
Re: Libraries using longjmp for error handling Kaz Kylheku <864-117-4973@kylheku.com> - 2023-09-28 23:11 +0000
Re: Libraries using longjmp for error handling Anton Shepelev <anton.txt@gmail.moc> - 2023-09-29 17:23 +0300
Re: Libraries using longjmp for error handling Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-09-29 08:19 -0700
Re: Libraries using longjmp for error handling David Brown <david.brown@hesbynett.no> - 2023-09-28 21:57 +0200
Re: Libraries using longjmp for error handling Richard Kettlewell <invalid@invalid.invalid> - 2023-09-30 09:37 +0100
Page 2 of 4 — ← Prev page 1 [2] 3 4 Next page →
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2023-10-02 02:31 -0700 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <865y3pe5gc.fsf@linuxsc.com> |
| In reply to | #176889 |
Ben Bacarisse <ben.usenet@bsb.me.uk> writes: > Tim Rentsch <tr.17687@z991.linuxsc.com> writes: > >> Ben Bacarisse <ben.usenet@bsb.me.uk> writes: >> >>> Tim Rentsch <tr.17687@z991.linuxsc.com> writes: >>> >>>> Ben Bacarisse <ben.usenet@bsb.me.uk> writes: >>>> >>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> writes: [...] >>>>>> [..example to illustrate using exceptions..] >>>>>> >>>>>> module TreeSet = struct >>>>>> type 'a treeset = Empty | Node of 'a treeset * 'a * 'a treeset >>>>>> exception Present >>>>>> >>>>>> let add tree element = >>>>>> let rec add t e = >>>>>> match t with >>>>>> | Empty -> Node( Empty, e, Empty ) >>>>>> | Node( a, v, b ) -> >>>>>> if e < v then Node( add a e, v, b ) else >>>>>> if e > v then Node( a, v, add b e ) else >>>>>> raise Present >>>>>> in >>>>>> try add tree element with Present -> tree >>>>>> >>>>>> end >>>>> >>>>> I'm not getting it. I'd write 'else t' rather than 'else raise >>>>> Present' and I could then do away with the wrapping 'add' function. >>>> >>>> Doing that would result in returning a valid tree, but it would also >>>> needlessly replicate all nodes starting from the point where the >>>> match was found and going up to the root. The consequence is more >>>> cycles used and more demand on the memory allocator. >>> >>> How can OCaml avoid making the allocations until it knows the exception >>> won't be raised? Are they not all still being done? >> >> No, no allocations are done if the to-be-added element is found >> (and so an exception is raised). Consider one of the lines where a >> Node is being constructed (which is synonymous with an allocation >> occurring): >> >> if e < v then Node( add a e, v, b ) else >> >> The call to the Node() constructor doesn't take place until the >> recursive call to 'add' returns. But if an equal value is found, >> then an exception is raised, and the call to 'add' does not /ever/ >> return. No return from 'add' means no Node() is constructed. > > Ah, yes. I was thinking in a lazy language (Haskell) while looking at > code in a strict one. Right. I was wondering if that might be the source of the confusion. Now that the question has come up, I don't know what it means to raise an exception in a language like Haskell where lazy evaluation is always in force. Does Haskell have exceptions? C is like OCaml in this respect in that lazy eval is possible but it needs to be explicit rather than just happening everywhere automatically.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2023-10-02 23:55 +0100 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <87o7hgbpmz.fsf@bsb.me.uk> |
| In reply to | #176919 |
Tim Rentsch <tr.17687@z991.linuxsc.com> writes: > Ben Bacarisse <ben.usenet@bsb.me.uk> writes: > >> Tim Rentsch <tr.17687@z991.linuxsc.com> writes: >> >>> Ben Bacarisse <ben.usenet@bsb.me.uk> writes: >>> >>>> Tim Rentsch <tr.17687@z991.linuxsc.com> writes: >>>> >>>>> Ben Bacarisse <ben.usenet@bsb.me.uk> writes: >>>>> >>>>>> Tim Rentsch <tr.17687@z991.linuxsc.com> writes: > [...] >>>>>>> [..example to illustrate using exceptions..] >>>>>>> >>>>>>> module TreeSet = struct >>>>>>> type 'a treeset = Empty | Node of 'a treeset * 'a * 'a treeset >>>>>>> exception Present >>>>>>> >>>>>>> let add tree element = >>>>>>> let rec add t e = >>>>>>> match t with >>>>>>> | Empty -> Node( Empty, e, Empty ) >>>>>>> | Node( a, v, b ) -> >>>>>>> if e < v then Node( add a e, v, b ) else >>>>>>> if e > v then Node( a, v, add b e ) else >>>>>>> raise Present >>>>>>> in >>>>>>> try add tree element with Present -> tree >>>>>>> >>>>>>> end >>>>>> >>>>>> I'm not getting it. I'd write 'else t' rather than 'else raise >>>>>> Present' and I could then do away with the wrapping 'add' function. >>>>> >>>>> Doing that would result in returning a valid tree, but it would also >>>>> needlessly replicate all nodes starting from the point where the >>>>> match was found and going up to the root. The consequence is more >>>>> cycles used and more demand on the memory allocator. >>>> >>>> How can OCaml avoid making the allocations until it knows the exception >>>> won't be raised? Are they not all still being done? >>> >>> No, no allocations are done if the to-be-added element is found >>> (and so an exception is raised). Consider one of the lines where a >>> Node is being constructed (which is synonymous with an allocation >>> occurring): >>> >>> if e < v then Node( add a e, v, b ) else >>> >>> The call to the Node() constructor doesn't take place until the >>> recursive call to 'add' returns. But if an equal value is found, >>> then an exception is raised, and the call to 'add' does not /ever/ >>> return. No return from 'add' means no Node() is constructed. >> >> Ah, yes. I was thinking in a lazy language (Haskell) while looking at >> code in a strict one. > > Right. I was wondering if that might be the source of the > confusion. Now that the question has come up, I don't know what > it means to raise an exception in a language like Haskell where > lazy evaluation is always in force. Does Haskell have exceptions? Yes it does, but I have not really wrapped my head around them. They throw you into the IO monad. > C is like OCaml in this respect in that lazy eval is possible but > it needs to be explicit rather than just happening everywhere > automatically. I knew OCaml was strict, I just had the wrong head on because the type system and matching are so similar. -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2023-10-03 05:01 -0700 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <86o7hfdieg.fsf@linuxsc.com> |
| In reply to | #177036 |
Ben Bacarisse <ben.usenet@bsb.me.uk> writes: > Tim Rentsch <tr.17687@z991.linuxsc.com> writes: > >> Ben Bacarisse <ben.usenet@bsb.me.uk> writes: [..setjmp()/longjmp() in other languages..] >>> Ah, yes. I was thinking in a lazy language (Haskell) while >>> looking at code in a strict one. >> >> Right. I was wondering if that might be the source of the >> confusion. Now that the question has come up, I don't know what >> it means to raise an exception in a language like Haskell where >> lazy evaluation is always in force. Does Haskell have exceptions? > > Yes it does, but I have not really wrapped my head around them. > They throw you into the IO monad. I see. :) Thank you for the info. It might be interesting to speculate what C would be like if it were lazy rather than eager. Maybe a lazy C could have the property that undefined behavior wouldn't happen unless it became essential to producing an output. Hmmm..
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.moc> |
|---|---|
| Date | 2023-09-29 23:58 +0300 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <20230929235846.a0883e001c83bbe718f5ab90@gmail.moc> |
| In reply to | #176735 |
Tim Rentsch: > kI wrote some code not long ago to add a value to a set of > values, where the set is represented using a recursive > binary tree structure (like red-black trees, but a little > different). Usually we may expect that a request to add a > value would offer a value not already included in the set, > but certainly it can happen that there is a call to add a > value that is already included, in which case the top > level return value should be the original tree structure. Returning an error flag (or code) all the way up the call stack may seem (and be) slow and cumbersome. If that case, one can rewrite the recursive function iteratively, with an explicit stack. I, however, think that an extra `if' in the recursive function is so much less fuss -- () ascii ribbon campaign -- against html e-mail /\ www.asciiribbon.org -- against proprietary attachments
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2023-10-01 02:52 -0700 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <86il7qekjo.fsf@linuxsc.com> |
| In reply to | #176760 |
Anton Shepelev <anton.txt@gmail.moc> writes: > Tim Rentsch: > >> I wrote some code not long ago to add a value to a set of >> values, where the set is represented using a recursive >> binary tree structure (like red-black trees, but a little >> different). Usually we may expect that a request to add a >> value would offer a value not already included in the set, >> but certainly it can happen that there is a call to add a >> value that is already included, in which case the top >> level return value should be the original tree structure. > > Returning an error flag (or code) all the way up the call > stack may seem (and be) slow and cumbersome. If that case, > one can rewrite the recursive function iteratively, with an > explicit stack. I, however, think that an extra `if' in the > recursive function is so much less fuss Besides making the code slower and substantially longer, the resulting code would take a lot more effort to read and understand. In most cases lots of if()'s means the code is poorly written and should be re-thought. In this particular case re-writing the code to be iterative rather than recursive, and using an explicit stack, is a total non-starter. It's good to know the theoretical result that recursion can be turned into iteration, but in practice the two approaches are often not interchangeable.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.moc> |
|---|---|
| Date | 2023-10-01 14:33 +0300 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <20231001143351.8f3425bd90185668acd28809@gmail.moc> |
| In reply to | #176854 |
Tim Rentsch to Anton Shepelev:
> > Returning an error flag (or code) all the way up the
> > call stack may seem (and be) slow and cumbersome. If
> > that case, one can rewrite the recursive function
> > iteratively, with an explicit stack. I, however, think
> > that an extra `if' in the recursive function is so much
> > less fuss
>
> Besides making the code slower and substantially longer,
Substantially slower along the unhappy path only.
Substantially lobger -- I don't think so, because regardless
of recursion depth, there is just one recursive function,
and if you want to handle a single type of error, you would
need a single extra `if' in it.
> the resulting code would take a lot more effort to read
> and understand.
Explicit control of execution flow is clearer for several
reasons:
1. No out-of-bandwith signalling.
2. Errors are handled uniformly with any other condigions
in the program using the same basic facilities.
3. Errors are handled where they occur, in a manner
visible to the programmer reading the piece code that
may produce errors.
> In most cases lots of if()'s means the code is poorly
> written and should be re-thought.
Programms are all about logic, making decisions. It is not
the quantity, but the quality of `if's that may indicate a
flaw in coding, e.g. because of the failure to use dependeny
injection correctly, passing many flags into called
functions, &c. The if-else-if-else... chain discussed in a
parallel thread is itself a set of many nested if
statements, but it is not considered good or bad coding
based on its length.
> In this particular case re-writing the code to be
> iterative rather than recursive, and using an explicit
> stack, is a total non-starter.
Perhaps, I have not tried it. When, however, I rewrote
quicksort in a interative manner I actually like the result!
> It's good to know the theoretical result that recursion
> can be turned into iteration, but in practice the two
> approaches are often not interchangeable.
Indeed. Recursion for readability, iteration with a stack
for performance.
--
() ascii ribbon campaign -- against html e-mail
/\ www.asciiribbon.org -- against proprietary attachments
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2023-09-28 01:48 +0100 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <877cobf7ht.fsf@bsb.me.uk> |
| In reply to | #176581 |
Blue-Maned_Hawk <bluemanedhawk@invalid.invalid> writes: > Richard Kettlewell wrote: > >> It’s more than 20 years since I last had to integrate a C library which >> reported errors via longjmp() and I’m still bitter about it. > > I have never encountered a library which does that. Which library was > that? > >> As a matter of API design, I’d rather C library communicated errors via >> return values (and pointer parameters, where more complex error >> information is required). > > Personally, i think that, at least for a library, an error should _only_ > be communicated by return value. If more complex information is required, > then the return value can be made more complex. I don't think i've ever > used a library that communicates information via a pointer parameter. Well you almost certainly have used such a library because some of the functions in the C standard library use this technique. For example, the failure to find a convertible sequence is signalled by strtod by what is placed in the pointer pointed to by the second argument. -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <864-117-4973@kylheku.com> |
|---|---|
| Date | 2023-09-28 05:11 +0000 |
| Message-ID | <20230927213652.767@kylheku.com> |
| In reply to | #176581 |
On 2023-09-27, Blue-Maned_Hawk <bluemanedhawk@invalid.invalid> wrote:
> Richard Kettlewell wrote:
>
>> It’s more than 20 years since I last had to integrate a C library which
>> reported errors via longjmp() and I’m still bitter about it.
>
> I have never encountered a library which does that. Which library was
> that?
libpng is one example. Given a png handle you can call png_setjmp(png)
to get a jmp_buf * pointer. You setjmp on it, and libpng will longjmp to
it. There is a png_longjmp(png, <val>) function you can tall to test it.
I seem to recall that there is at least one more "famous" library which
similarly uses longjmp, but I cannot remember which.
Supporting this kind of library in the TXR Lisp FFI has been on my
TODO list. Seeing this thread gave me the sudden impetus to get it
working, and I got it done.
This works:
(let ((jb (jmp-buf)))
(setjmp jb result
(progn (put-line "setjmp")
(longjmp jb 42))
(put-line `result @result`)))
There is a jmp-buf function that allocates and returns a blank
object suitable as a jump buffer. There is a setjmp macro
which saves the context and evaluates a form. That form can longjmp,
in which case zero or more longjmp cleanup forms are evaluated
in scope of a variable which is bound to the integer longjmp
value.
I didn't have to add any special operator; setjmp expands to
a call to a run-time support function, where the expression
arguments are shored up into lambda functions.
In the test case file, in addition to the above trivial test,
I detect whether the system has libpng installed. If so,
a FFI test with libpng is conducted:
;; needed by png-set-longjmp-fn API
(defvarl libc (dlopen nil))
(defvarl longjmp-addr (dlsym libc "longjmp"))
(typedef png-structp (cptr png))
(with-dyn-lib "libpng.so"
(deffi png-get-header-ver "png_get_header_ver" str (png-structp))
(deffi png-create-read-struct "png_create_read_struct" png-structp (str cptr cptr cptr))
(deffi png-set-longjmp-fn "png_set_longjmp_fn" (carray uchar) (png-structp (cptr dlsym) size-t))
(deffi png-longjmp "png_longjmp" void (png-structp int)))
(defvar png-ver (png-get-header-ver cptr-null))
;; In the png.h header, png_setjmp is a macro only; you cannot
;; #undef it to get to a function. So we write the macro in
;; the same way as a Lisp macro, in terms of png-set-longjmp-fn,
;; whereby we pass the longjmp function, and sizeof (jmp_buf).
(defmacro png-setjmp (png-ptr)
(let ((jmpbuf-size (load-time (len (jmp-buf)))))
^(png-set-longjmp-fn ,png-ptr longjmp-addr ,jmpbuf-size)))
;;; Test
;; get png handle
(defvar png (png-create-read-struct png-ver cptr-null cptr-null cptr-null))
With that we can get the jmp-buf out of png, setjmp on it,
and then invoke it via png_longjmp, as if the library generated
an error:
;; get jmp_buf from png handle, setjmp it, longjmp to it.
(setjmp (png-setjmp png) err
(progn (put-line "libpng longjmp")
(png-longjmp png 42))
(put-line `libpng error @err`))
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca
NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <864-117-4973@kylheku.com> |
|---|---|
| Date | 2023-09-28 06:26 +0000 |
| Message-ID | <20230927232455.602@kylheku.com> |
| In reply to | #176606 |
On 2023-09-28, Kaz Kylheku <864-117-4973@kylheku.com> wrote: > On 2023-09-27, Blue-Maned_Hawk <bluemanedhawk@invalid.invalid> wrote: >> Richard Kettlewell wrote: >> >>> It’s more than 20 years since I last had to integrate a C library which >>> reported errors via longjmp() and I’m still bitter about it. >> >> I have never encountered a library which does that. Which library was >> that? > > libpng is one example. Given a png handle you can call png_setjmp(png) > to get a jmp_buf * pointer. You setjmp on it, and libpng will longjmp to > it. There is a png_longjmp(png, <val>) function you can tall to test it. Found another one: netpbm. With netpbm, you allocate the jmp_buf, save context with setjmp and pass the jmp_buf to pm_setjmpbuf. It will then longjmp through it in an error situation.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.moc> |
|---|---|
| Date | 2023-09-28 16:02 +0300 |
| Message-ID | <20230928160237.9796f1896cb0be293bd24b76@gmail.moc> |
| In reply to | #176581 |
Blue-Maned_Hawk: > Personally, i think that, at least for a library, an error > should _only_ be communicated by return value. If more > complex information is required, then the return value can > be made more complex. I don't think i've ever used a > library that communicates information via a pointer > parameter. The failure to captrue the return value and to test it for an error is a classic code smell, which is possible because the return value can be ignored. If the error be signalled via an output parameter[1], however, it is much harder to ignore it, becuase the programmer is forced to declare a local variable to hold the error information and pass it to the invocation. This frees the return value for the actual function result, and then again the programmer cannot ignore it but must use somehow, lest the invocation be pointess. The above seems to suggest that the unusual practice of signalling an error via an output parameter is preferable from at lest the viewpoint of encouraging the programmer to handle errors... Furthermore, it is rather annoying in a language with a single return value, to have that primary ouput channel used to signal errors, forcing the programmer to resort the auxiliary channel of ouput parameters to return actual results. Yes, I do it all the time, and your post may prompt me to try the alternative. ____________________ 1. In C, this would be a pointer, but I am using higher- level terminology. -- () ascii ribbon campaign -- against html e-mail /\ www.asciiribbon.org -- against proprietary attachments
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2023-09-28 14:44 +0100 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <87jzsae7jm.fsf@bsb.me.uk> |
| In reply to | #176647 |
Anton Shepelev <anton.txt@gmail.moc> writes:
> Blue-Maned_Hawk:
>
>> Personally, i think that, at least for a library, an error
>> should _only_ be communicated by return value. If more
>> complex information is required, then the return value can
>> be made more complex. I don't think i've ever used a
>> library that communicates information via a pointer
>> parameter.
>
> The failure to captrue the return value and to test it for
> an error is a classic code smell, which is possible because
> the return value can be ignored. If the error be signalled
> via an output parameter[1], however, it is much harder to
> ignore it, becuase the programmer is forced to declare a
> local variable to hold the error information and pass it to
> the invocation.
To nit-pick a bit, in C, there is no need to declare anything if you
want to ignore an "output parameter". Taking strtod as a (poor)
example:
double d = strtod(str, &(char *){0});
Of course strtod allows you to pass a null pointer here anyway, but
that's not the point. One can always pass a temporary object.
> This frees the return value for the actual
> function result, and then again the programmer cannot ignore
> it but must use somehow, lest the invocation be pointess.
> The above seems to suggest that the unusual practice of
> signalling an error via an output parameter is preferable
> from at lest the viewpoint of encouraging the programmer to
> handle errors...
This may be the case in C (where tagged union return values would be a
pain in the neck), but in other languages I'd say it's backwards. If
the error is a valid but alternate return value the programmer /can't/
ignore it.
> Furthermore, it is rather annoying in a language with a
> single return value, to have that primary ouput channel used
> to signal errors, forcing the programmer to resort the
> auxiliary channel of ouput parameters to return actual
> results. Yes, I do it all the time, and your post may
> prompt me to try the alternative.
One solution, in other languages, is to provide a simple way to use that
primary channel for both. Every call would have to code to handle the
options, even if that ended up being explict "ignore everything but the
successful return" code.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.moc> |
|---|---|
| Date | 2023-09-28 18:31 +0300 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <20230928183129.fb386b543c40cd56340ca40f@gmail.moc> |
| In reply to | #176650 |
Ben Bacarisse to Anton Shepelev:
> To nit-pick a bit, in C, there is no need to declare
> anything if you want to ignore an "output parameter".
> Taking strtod as a (poor) example:
>
> double d = strtod(str, &(char *){0});
Ah, but this is one of the strangest and craziest
innovations of post-modern C -- the ability to pass a
pointer (as it were) to a literal, rather than to a proper
variable. I say post-modern, because the adjective has just
the right connotations of surrealism, abstract art. I
hadn't even thought of doing that. Programming languages
seem obsessed with letting the programmer do as much as
possible in place and inline: treating everyting as an
expression, the comma operator, the ternary conditional
operator, lambdas, anonymous functions and types, and
now -- anonymous variables or literals -- to the detriment
of the academic approach of giving every thing its own
identifer.
> > The above seems to suggest that the unusual practice of
> > signalling an error via an output parameter is
> > preferable from at lest the viewpoint of encouraging the
> > programmer to handle errors...
>
> This may be the case in C (where tagged union return
> values would be a pain in the neck), but in other
> languages I'd say it's backwards. If the error is a valid
> but alternate return value the programmer /can't/ ignore
> it.
He can still work with the tagged union as if the error-
member did not exist. He can still treat the return value
as if it always contained the result of a successful
invocation. With the output parameter, ignoring an error
requires some effort, and that effort is visible in the
code, e.g. as a dummy variable whose value is never used.
> > Furthermore, it is rather annoying in a language with a
> > single return value, to have that primary ouput channel
> > used to signal errors, forcing the programmer to resort
> > the auxiliary channel of ouput parameters to return
> > actual results. Yes, I do it all the time, and your
> > post may prompt me to try the alternative.
>
> One solution, in other languages, is to provide a simple
> way to use that primary channel for both. Every call
> would have to code to handle the options, even if that
> ended up being explict "ignore everything but the
> successful return" code.
Am I right that implementing that "simple" method is a major
difficulty in compiler design?
--
() ascii ribbon campaign -- against html e-mail
/\ www.asciiribbon.org -- against proprietary attachments
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <864-117-4973@kylheku.com> |
|---|---|
| Date | 2023-09-28 16:43 +0000 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <20230928093424.111@kylheku.com> |
| In reply to | #176655 |
On 2023-09-28, Anton Shepelev <anton.txt@gmail.moc> wrote:
> Ben Bacarisse to Anton Shepelev:
>
>> To nit-pick a bit, in C, there is no need to declare
>> anything if you want to ignore an "output parameter".
>> Taking strtod as a (poor) example:
>>
>> double d = strtod(str, &(char *){0});
>
> Ah, but this is one of the strangest and craziest
> innovations of post-modern C -- the ability to pass a
> pointer (as it were) to a literal, rather than to a proper
> variable.
Two things:
Firstly, it's not a true literal because it is a mutable object in
automatic storage.
Each time control flow enters the scope where "double d" is defined, a
new object is created.
A plausible translation scheme for the &(char *){0} object in
the above situation is to emit a hidden variable, like this:
char *__hidden_1234 = 0;
double d = strtod(str, &__hidden_1234);
The only literal in sight is the 0 constant.
(Rather it is C++ that has the weird design of being able to bind const
references to literals that are of a type whose values don't have
reference semantics.)
Secondly, we have had pointers to literals for over seventy years,
ever since Lisp:
(function '(1 2 3)) ;; literal list passed to function
Quoted lists are bona fide literals in Lisp. Common Lisp makes
it undefined behavior to try to modify them; they can be burned
into ROM or mapped into read-only VM pages and such.
Quoted lists with identical suffixes can be merged together (sound
familiar?), and since they are constants, they can be subject to
constant folding so that they partially or entirely disappear. E.g.(cdr
'(1 2 3)) can compile into '(2 3).
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca
NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2023-09-28 17:00 +0000 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <cjiRM.52588$wO91.11826@fx39.iad> |
| In reply to | #176657 |
Kaz Kylheku <864-117-4973@kylheku.com> writes:
>On 2023-09-28, Anton Shepelev <anton.txt@gmail.moc> wrote:
>> Ben Bacarisse to Anton Shepelev:
>>
>>> To nit-pick a bit, in C, there is no need to declare
>>> anything if you want to ignore an "output parameter".
>>> Taking strtod as a (poor) example:
>>>
>>> double d = strtod(str, &(char *){0});
>>
>> Ah, but this is one of the strangest and craziest
>> innovations of post-modern C -- the ability to pass a
>> pointer (as it were) to a literal, rather than to a proper
>> variable.
>
>Two things:
>
>Firstly, it's not a true literal because it is a mutable object in
>automatic storage.
Perhaps Ben should have written it as
double d= strtod(str, NULL);
RETURN VALUE
These functions return the converted value, if any.
If endptr is not NULL, a pointer to the character after the last char-
acter used in the conversion is stored in the location referenced by
endptr.
This will just push a zero to the stack (or argument register) before calling
strtod. No need to allocate storage anywhere.
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <864-117-4973@kylheku.com> |
|---|---|
| Date | 2023-09-28 17:16 +0000 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <20230928101336.603@kylheku.com> |
| In reply to | #176659 |
On 2023-09-28, Scott Lurndal <scott@slp53.sl.home> wrote:
> Kaz Kylheku <864-117-4973@kylheku.com> writes:
>>On 2023-09-28, Anton Shepelev <anton.txt@gmail.moc> wrote:
>>> Ben Bacarisse to Anton Shepelev:
>>>
>>>> To nit-pick a bit, in C, there is no need to declare
>>>> anything if you want to ignore an "output parameter".
>>>> Taking strtod as a (poor) example:
>>>>
>>>> double d = strtod(str, &(char *){0});
>>>
>>> Ah, but this is one of the strangest and craziest
>>> innovations of post-modern C -- the ability to pass a
>>> pointer (as it were) to a literal, rather than to a proper
>>> variable.
>>
>>Two things:
>>
>>Firstly, it's not a true literal because it is a mutable object in
>>automatic storage.
>
> Perhaps Ben should have written it as
>
> double d= strtod(str, NULL);
Check Ben's original post. That was mentioned from the start, but set
aside for the sake of illustrating how you can ignore an "output
parameter" which doesn't have such a NULL opt-out mechanism, and
to do it in a self-contained way, without the clutter of separately
declaring temporary objects.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca
NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2023-09-28 19:38 +0100 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <8734yydtyg.fsf@bsb.me.uk> |
| In reply to | #176659 |
scott@slp53.sl.home (Scott Lurndal) writes:
> Kaz Kylheku <864-117-4973@kylheku.com> writes:
>>On 2023-09-28, Anton Shepelev <anton.txt@gmail.moc> wrote:
>>> Ben Bacarisse to Anton Shepelev:
>>>
>>>> To nit-pick a bit, in C, there is no need to declare
>>>> anything if you want to ignore an "output parameter".
>>>> Taking strtod as a (poor) example:
>>>>
>>>> double d = strtod(str, &(char *){0});
>>>
>>> Ah, but this is one of the strangest and craziest
>>> innovations of post-modern C -- the ability to pass a
>>> pointer (as it were) to a literal, rather than to a proper
>>> variable.
>>
>>Two things:
>>
>>Firstly, it's not a true literal because it is a mutable object in
>>automatic storage.
>
> Perhaps Ben should have written it as
>
> double d= strtod(str, NULL);
No, for reasons I gave! The point was that one can always do at least
this so there is never a need for a declared variable when the
information is going to be ignored.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2023-09-28 16:05 -0700 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <8634yxj3uh.fsf@linuxsc.com> |
| In reply to | #176657 |
Kaz Kylheku <864-117-4973@kylheku.com> writes:
> On 2023-09-28, Anton Shepelev <anton.txt@gmail.moc> wrote:
>
>> Ben Bacarisse to Anton Shepelev:
>>
>>> To nit-pick a bit, in C, there is no need to declare
>>> anything if you want to ignore an "output parameter".
>>> Taking strtod as a (poor) example:
>>>
>>> double d = strtod(str, &(char *){0});
>>
>> Ah, but this is one of the strangest and craziest
>> innovations of post-modern C -- the ability to pass a
>> pointer (as it were) to a literal, rather than to a proper
>> variable.
>
> Two things:
>
> Firstly, it's not a true literal because it is a mutable object in
> automatic storage.
It most definitely is a literal, both in the original meaning
of the word, and also as used in the ISO C standard.
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <864-117-4973@kylheku.com> |
|---|---|
| Date | 2023-09-29 00:26 +0000 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <20230928161154.506@kylheku.com> |
| In reply to | #176679 |
On 2023-09-28, Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
> Kaz Kylheku <864-117-4973@kylheku.com> writes:
>
>> On 2023-09-28, Anton Shepelev <anton.txt@gmail.moc> wrote:
>>
>>> Ben Bacarisse to Anton Shepelev:
>>>
>>>> To nit-pick a bit, in C, there is no need to declare
>>>> anything if you want to ignore an "output parameter".
>>>> Taking strtod as a (poor) example:
>>>>
>>>> double d = strtod(str, &(char *){0});
>>>
>>> Ah, but this is one of the strangest and craziest
>>> innovations of post-modern C -- the ability to pass a
>>> pointer (as it were) to a literal, rather than to a proper
>>> variable.
>>
>> Two things:
>>
>> Firstly, it's not a true literal because it is a mutable object in
>> automatic storage.
>
> It most definitely is a literal, both in the original meaning
Let's examine our use of the article "a".
#include <stdio.h>
void fun(int c)
{
char x;
if (c > 0) {
printf("%p\n", (void *) &(char *){&x});
fun(c - 1);
}
}
int main(void)
{
fun(5);
return 0;
}
$ ./literal
0xbfd9f4b8
0xbfd9f488
0xbfd9f458
0xbfd9f428
0xbfd9f3f8
This illustrates why I have an issue with using the term "literal" for
this situation.
The object:
1. (by default) is freshly allocated on the fly in automatic storage;
2. consequently, may exhibit multiple addresses concurrently;
3. is destroyed when the scope terminates;
4. is independently mutable in all its multiple instances; and
5. doesn't have literals in its expression, being initialized using &x.
What is literal about it?
C99 said that a compound literal "is an expression that provides access
to an anonymous object".
Why can't we call that expression "anonymous object designator"
or something? If we have "char *p = 0", p is a primary expression which
designates an object, and not a literal.
If we then have (char *){p} we get an anonymous object that is
initialized with a copy of p, and that expression designates it in much
the same way as p designates its object.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca
NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2023-09-28 23:20 -0700 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <86h6ndh55s.fsf@linuxsc.com> |
| In reply to | #176686 |
Kaz Kylheku <864-117-4973@kylheku.com> writes:
> On 2023-09-28, Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>
>> Kaz Kylheku <864-117-4973@kylheku.com> writes:
>>
>>> On 2023-09-28, Anton Shepelev <anton.txt@gmail.moc> wrote:
>>>
>>>> Ben Bacarisse to Anton Shepelev:
>>>>
>>>>> To nit-pick a bit, in C, there is no need to declare
>>>>> anything if you want to ignore an "output parameter".
>>>>> Taking strtod as a (poor) example:
>>>>>
>>>>> double d = strtod(str, &(char *){0});
>>>>
>>>> Ah, but this is one of the strangest and craziest
>>>> innovations of post-modern C -- the ability to pass a
>>>> pointer (as it were) to a literal, rather than to a proper
>>>> variable.
>>>
>>> Two things:
>>>
>>> Firstly, it's not a true literal because it is a mutable object in
>>> automatic storage.
>>
>> It most definitely is a literal, both in the original meaning
>
> Let's examine our use of the article "a".
>
> #include <stdio.h>
>
> void fun(int c)
> {
> char x;
>
> if (c > 0) {
> printf("%p\n", (void *) &(char *){&x});
> fun(c - 1);
> }
> }
>
> [...]
> What is literal about it?
It refers an anonymous object whose initial value is determined
by the tokens making up the literal. That meaning of the term
"literal" is about 60 years old. (That meaning didn't use the
word "object" but did refer to memory that in the context of
the C standard would be called an object.)
> C99 said that a compound literal "is an expression that
> provides access to an anonymous object".
>
> Why can't we call that expression "anonymous object designator"
> or something? If we have "char *p = 0", p is a primary
> expression which designates an object, and not a literal.
You could call it a rhinoceros if you wanted to, but that
wouldn't change what the C standard calls it, or what the
original meaning of the word literal is, or that both the
term compound literal and the orginal meaning of literal
share the key property of referring to an anonymous object.
> If we then have (char *){p} we get an anonymous object that is
> initialized with a copy of p, and that expression designates it
> in much the same way as p designates its object.
They differ in one key respect: in the case of a variable, we
have to give the variable a name, and refer to the object by its
name, but in the case of a compound literal, there is no name,
and we refer to the object "by what it is". That's why it's
called a literal.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2023-09-28 18:31 -0700 |
| Subject | Re: Libraries using longjmp for error handling |
| Message-ID | <87a5t5sr2j.fsf@nosuchdomain.example.com> |
| In reply to | #176679 |
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
> Kaz Kylheku <864-117-4973@kylheku.com> writes:
>
>> On 2023-09-28, Anton Shepelev <anton.txt@gmail.moc> wrote:
>>
>>> Ben Bacarisse to Anton Shepelev:
>>>
>>>> To nit-pick a bit, in C, there is no need to declare
>>>> anything if you want to ignore an "output parameter".
>>>> Taking strtod as a (poor) example:
>>>>
>>>> double d = strtod(str, &(char *){0});
>>>
>>> Ah, but this is one of the strangest and craziest
>>> innovations of post-modern C -- the ability to pass a
>>> pointer (as it were) to a literal, rather than to a proper
>>> variable.
>>
>> Two things:
>>
>> Firstly, it's not a true literal because it is a mutable object in
>> automatic storage.
>
> It most definitely is a literal, both in the original meaning
> of the word, and also as used in the ISO C standard.
C doesn't not define what the word "literal" means. It has no syntactic
category called "literal". It has distinct constructs "string literal"
and "compound literal".
You've asserted in the past that there's a logical reason behind using
the term "literal" for these two constructs and not for others, such as
integer constants. I'm not particularly interested in debating that
point again, but I see no support in the standard for that assertion.
(The standard also uses the word "literal" as an adjective; see for
example N1570 6.1p1 where it refers to terminals in the grammar.)
My point is that any discussion of what is or is not a "true literal" is
unlikely to yield any meaningful result.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
Page 2 of 4 — ← Prev page 1 [2] 3 4 Next page →
Back to top | Article view | comp.lang.c
csiph-web