Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #145998 > unrolled thread
| Started by | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| First post | 2019-09-04 14:14 -0700 |
| Last post | 2019-09-05 08:43 -0700 |
| Articles | 15 on this page of 55 — 14 participants |
Back to article view | Back to comp.lang.c
error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-04 14:14 -0700
Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-04 15:20 -0700
Re: error_t proposal Mateusz Viste <mateusz@wont.tell> - 2019-09-05 08:02 +0000
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 04:04 -0700
Re: error_t proposal Bruce S <bruces42@hotmail.com> - 2019-09-05 08:18 -0600
Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-05 14:31 -0700
Re: error_t proposal James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-09-05 17:49 -0400
Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-05 15:14 -0700
Re: error_t proposal Bruce S <bruces42@hotmail.com> - 2019-09-06 14:03 -0600
Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-05 09:30 +1000
Re: error_t proposal Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-05 02:38 -0700
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 04:57 -0700
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 05:16 -0700
Re: error_t proposal Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-05 05:35 -0700
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 06:08 -0700
Re: error_t proposal Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-05 06:16 -0700
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 06:37 -0700
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 07:04 -0700
Re: error_t proposal Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-09-05 20:51 +0100
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 13:52 -0700
Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-05 14:56 -0700
Re: error_t proposal William Ahern <william@25thandClement.com> - 2019-09-05 13:18 -0700
Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-06 07:25 +1000
Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-06 07:35 +1000
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-06 04:22 -0700
Re: error_t proposal scott@slp53.sl.home (Scott Lurndal) - 2019-09-05 13:59 +0000
Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-06 07:10 +1000
Re: error_t proposal Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-09-05 10:01 +0000
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 04:36 -0700
Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-05 14:43 -0700
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-06 05:01 -0700
Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-06 11:18 -0700
Re: error_t proposal scott@slp53.sl.home (Scott Lurndal) - 2019-09-06 19:34 +0000
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-06 12:37 -0700
Re: error_t proposal Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-09-06 20:54 +0100
Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-06 13:20 -0700
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-06 13:43 -0700
Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-06 14:25 -0700
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-06 15:14 -0700
Re: error_t proposal Keith Thompson <kst-u@mib.org> - 2019-09-06 15:49 -0700
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-06 18:44 -0700
Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-07 12:35 +1000
Re: error_t proposal Ike Naar <ike@sdf.lonestar.org> - 2019-09-08 20:15 +0000
Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-09 09:30 +1000
Re: error_t proposal Ike Naar <ike@iceland.freeshell.org> - 2019-09-09 07:35 +0000
Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-09 19:44 +1000
Re: error_t proposal scott@slp53.sl.home (Scott Lurndal) - 2019-09-09 13:58 +0000
Re: error_t proposal Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-09-10 14:24 +0000
Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-11 09:22 +1000
Re: error_t proposal Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-10 16:48 -0700
Re: error_t proposal Clifford Heath <no.spam@please.net> - 2019-09-11 10:45 +1000
Re: error_t proposal Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-09-06 21:47 +0100
Re: error_t proposal jadill33@gmail.com - 2019-09-05 07:04 -0700
Re: error_t proposal Thiago Adams <thiago.adams@gmail.com> - 2019-09-05 07:36 -0700
Re: error_t proposal jadill33@gmail.com - 2019-09-05 08:43 -0700
Page 3 of 3 — ← Prev page 1 2 [3]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-09-06 18:44 -0700 |
| Message-ID | <32ae196a-b38b-43e4-a09d-561a5d2e5aa6@googlegroups.com> |
| In reply to | #146085 |
On Friday, September 6, 2019 at 7:49:26 PM UTC-3, Keith Thompson wrote: > Thiago Adams writes: > > On Friday, September 6, 2019 at 6:25:27 PM UTC-3, Keith Thompson wrote: > [...] > >> If you want to define your own error type, I suggest *not* calling it > >> "errno_t" as C11 Annex K does. Support for Annex K is not widespread, > >> and it's been proposed for removal in the next edition. > >> > >> <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1969.htm#adi> > > > > I think they should do a fix. In the worst case just ignore the > > extra arguments and leave it for static analysis. > > I don't think that will happen. > > >> I like the idea of a consistent error reporting convention for library > >> functions, but existing and widely used libraries are *not* consistent, > >> and that's not going to change any time soon. What is the intended > >> scope of your proposal? > > Sorry, I didn't understand you question. > > For example, are you pushing for POSIX and other standards/libraries to > be updated to adopt your proposal? Or just newly designed libraries? > Or just your own? I think it is not possible to change the existing POSIX interfaces because the function contract would be broken. The current contract is " On success, zero is returned. On error, -1 is returned, and errno is set appropriately. " So it would not be possible to return errno . For our own libraries the advantage is not having to create/define/maintain/remember/document/explain a header file with a exclusive error type. For a C community the advantage is the similar. As soon as you read errno_t from a thirty party lib you will understand. And conversion between MyLibError and YourLibError and StardandLib error would not be necessary. One situation where I think this idea should have been used is here int thrd_create( thrd_t *thr, thrd_start_t func, void *arg ); If you look at C++ they are using POSIX as the abstraction layer. I think this is correct. The thing I think is bad in C++ is the over-engineering, for instance, in the error type. https://en.cppreference.com/w/cpp/error/error_code or chrono https://en.cppreference.com/w/cpp/chrono/time_point iostream and more. What I would like to see is a simple typedef errno_t not depending on Annex K and POSIX constants added into C. Note that they already included in C++. As a bonus, I would like to see more POSIX functions added into C especially file system. In this case the contract could be new and returning errno_t . For instance: (this is C++) https://en.cppreference.com/w/cpp/filesystem/remove The notes says everthing: "Notes On POSIX systems, this function typically calls unlink and rmdir as needed, on Windows RemoveDirectoryW and DeleteFileW." I would like to see in C errno_t remove(const char* path);
[toc] | [prev] | [next] | [standalone]
| From | Clifford Heath <no.spam@please.net> |
|---|---|
| Date | 2019-09-07 12:35 +1000 |
| Message-ID | <VHEcF.199857$9i3.11349@fx42.iad> |
| In reply to | #146086 |
On 7/9/19 11:44 am, Thiago Adams wrote: > On Friday, September 6, 2019 at 7:49:26 PM UTC-3, Keith Thompson wrote: >> Thiago Adams writes: >>> On Friday, September 6, 2019 at 6:25:27 PM UTC-3, Keith Thompson wrote: >> [...] >>>> If you want to define your own error type, I suggest *not* calling it >>>> "errno_t" as C11 Annex K does. Support for Annex K is not widespread, >>>> and it's been proposed for removal in the next edition. >>>> >>>> <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1969.htm#adi> >>> >>> I think they should do a fix. In the worst case just ignore the >>> extra arguments and leave it for static analysis. >> >> I don't think that will happen. >> >>>> I like the idea of a consistent error reporting convention for library >>>> functions, but existing and widely used libraries are *not* consistent, >>>> and that's not going to change any time soon. What is the intended >>>> scope of your proposal? >>> Sorry, I didn't understand you question. >> >> For example, are you pushing for POSIX and other standards/libraries to >> be updated to adopt your proposal? Or just newly designed libraries? >> Or just your own? > > I think it is not possible to change the existing POSIX interfaces > because the function contract would be broken. > The current contract is > " > On success, zero is returned. On error, -1 is returned, and errno is > set appropriately. > " > > So it would not be possible to return errno . > > For our own libraries the advantage is not having to > create/define/maintain/remember/document/explain a header > file with a exclusive error type. On the other hand one could augment the existing contract. For example, an ENOSPC error while writing a file can still be set in errno, but a support library could also set an additional variable (error parameter) to the name of the device that is out of space. Even just an fstat() to get the inode details from the fd would be a damn good start. By providing the context that *should have been returned by the OS* you reduce the impedance that a developer has to chasing the details of a rare error on every possible time that they might need to report it. The fact that there is so rarely value in such a lot of effort is the problem here - but when the problem does occur, the end user often needs more help. Developers just shrug and say "you should learn how to use your computer" - i.e. the problem is with the user, not with themselves. This is the fundamental disrespect that is enshrined in Posix and errno. -- Clifford Heath. > For a C community the advantage is the similar. As soon as you read > errno_t from a thirty party lib you will understand. > And conversion between MyLibError and YourLibError and StardandLib > error would not be necessary. > One situation where I think this idea should have been used is here > int thrd_create( thrd_t *thr, thrd_start_t func, void *arg ); > > If you look at C++ they are using POSIX as the abstraction layer. > I think this is correct. The thing I think is bad in C++ is the > over-engineering, for instance, in the error type. > https://en.cppreference.com/w/cpp/error/error_code > or chrono > https://en.cppreference.com/w/cpp/chrono/time_point > iostream and more. > > What I would like to see is a simple typedef errno_t not depending > on Annex K and POSIX constants added into C. Note that they already > included in C++. > > As a bonus, I would like to see more POSIX functions added into C > especially file system. > In this case the contract could be new and returning errno_t . > For instance: (this is C++) > > https://en.cppreference.com/w/cpp/filesystem/remove > > > The notes says everthing: > > "Notes > On POSIX systems, this function typically calls unlink and rmdir as needed, on Windows RemoveDirectoryW and DeleteFileW." > > I would like to see in C > > errno_t remove(const char* path); > >
[toc] | [prev] | [next] | [standalone]
| From | Ike Naar <ike@sdf.lonestar.org> |
|---|---|
| Date | 2019-09-08 20:15 +0000 |
| Message-ID | <slrn3ht8qnaob4.fpt.ike@sdf.lonestar.org> |
| In reply to | #146087 |
On 2019-09-07, Clifford Heath <no.spam@please.net> wrote: > On the other hand one could augment the existing contract. > > For example, an ENOSPC error while writing a file can still be set in > errno, but a support library could also set an additional variable > (error parameter) to the name of the device that is out of space. Even > just an fstat() to get the inode details from the fd would be a damn > good start. Is this really necessary? If some function, taking a file argument, returs ENOSPC, the caller knows the file for which error condition happened, so if the caller would be interested in the device, the caller could extract this information via other means.
[toc] | [prev] | [next] | [standalone]
| From | Clifford Heath <no.spam@please.net> |
|---|---|
| Date | 2019-09-09 09:30 +1000 |
| Message-ID | <6agdF.238076$Yo.220135@fx08.iad> |
| In reply to | #146096 |
On 9/9/19 6:15 am, Ike Naar wrote: > On 2019-09-07, Clifford Heath <no.spam@please.net> wrote: >> On the other hand one could augment the existing contract. >> >> For example, an ENOSPC error while writing a file can still be set in >> errno, but a support library could also set an additional variable >> (error parameter) to the name of the device that is out of space. Even >> just an fstat() to get the inode details from the fd would be a damn >> good start. > > Is this really necessary? > If some function, taking a file argument, returs ENOSPC, the caller > knows the file for which error condition happened, so if the caller > would be interested in the device, the caller could extract this > information via other means. Yes, it is necessary, both in this case and in other cases, even though there may be a round-about way of discovering the cause. The culture of laziness that engendered this omission is the same culture that results in omission of other detail, caricatured eventually by "Unknown Error 0x80000000" type reporting. It's too hard to handle every error that might follow from a write() call, so coders end up simply saying "Can't save your project" or something even less useful, and leaving the end user guessing at why. Every single error has a concrete context and cause, and we need to make a radical commitment to actually reporting the details (all the time but most particularly at the operating system level) - as well as the final consequences. Failure to properly report details that are available is the single thing that most infuriates users, and rightly so. This is why our users hate us. Clifford Heath.
[toc] | [prev] | [next] | [standalone]
| From | Ike Naar <ike@iceland.freeshell.org> |
|---|---|
| Date | 2019-09-09 07:35 +0000 |
| Message-ID | <slrn3km4qnc062.f0h.ike@iceland.freeshell.org> |
| In reply to | #146097 |
On 2019-09-08, Clifford Heath <no.spam@please.net> wrote: > On 9/9/19 6:15 am, Ike Naar wrote: >> On 2019-09-07, Clifford Heath <no.spam@please.net> wrote: >>> On the other hand one could augment the existing contract. >>> >>> For example, an ENOSPC error while writing a file can still be set in >>> errno, but a support library could also set an additional variable >>> (error parameter) to the name of the device that is out of space. Even >>> just an fstat() to get the inode details from the fd would be a damn >>> good start. >> >> Is this really necessary? >> If some function, taking a file argument, returs ENOSPC, the caller >> knows the file for which error condition happened, so if the caller >> would be interested in the device, the caller could extract this >> information via other means. > > Yes, it is necessary, both in this case and in other cases, even though > there may be a round-about way of discovering the cause. > > The culture of laziness that engendered this omission is the same > culture that results in omission of other detail, caricatured eventually > by "Unknown Error 0x80000000" type reporting. It's too hard to handle > every error that might follow from a write() call, so coders end up > simply saying "Can't save your project" or something even less useful, > and leaving the end user guessing at why. > > Every single error has a concrete context and cause, and we need to make > a radical commitment to actually reporting the details (all the time but > most particularly at the operating system level) - as well as the final > consequences. Failure to properly report details that are available is > the single thing that most infuriates users, and rightly so. > > This is why our users hate us. If the caller of write() is not willing to report the details when write() returns an error, then what would be the benefit if write() would provide those details in some alternative fashion?
[toc] | [prev] | [next] | [standalone]
| From | Clifford Heath <no.spam@please.net> |
|---|---|
| Date | 2019-09-09 19:44 +1000 |
| Message-ID | <vapdF.206347$9i3.183161@fx42.iad> |
| In reply to | #146098 |
On 9/9/19 5:35 pm, Ike Naar wrote: > On 2019-09-08, Clifford Heath <no.spam@please.net> wrote: >> On 9/9/19 6:15 am, Ike Naar wrote: >>> On 2019-09-07, Clifford Heath <no.spam@please.net> wrote: >>>> On the other hand one could augment the existing contract. >>>> >>>> For example, an ENOSPC error while writing a file can still be set in >>>> errno, but a support library could also set an additional variable >>>> (error parameter) to the name of the device that is out of space. Even >>>> just an fstat() to get the inode details from the fd would be a damn >>>> good start. >>> >>> Is this really necessary? >>> If some function, taking a file argument, returs ENOSPC, the caller >>> knows the file for which error condition happened, so if the caller >>> would be interested in the device, the caller could extract this >>> information via other means. >> >> Yes, it is necessary, both in this case and in other cases, even though >> there may be a round-about way of discovering the cause. >> >> The culture of laziness that engendered this omission is the same >> culture that results in omission of other detail, caricatured eventually >> by "Unknown Error 0x80000000" type reporting. It's too hard to handle >> every error that might follow from a write() call, so coders end up >> simply saying "Can't save your project" or something even less useful, >> and leaving the end user guessing at why. >> >> Every single error has a concrete context and cause, and we need to make >> a radical commitment to actually reporting the details (all the time but >> most particularly at the operating system level) - as well as the final >> consequences. Failure to properly report details that are available is >> the single thing that most infuriates users, and rightly so. >> >> This is why our users hate us. > > If the caller of write() is not willing to report the details when > write() returns an error, then what would be the benefit if write() > would provide those details in some alternative fashion? > It's all about impedance. If errno was augmented with (thread-safe) parameter variables, and if strerror() contained printf substitutions or made use of the returned error parameters to format a customised message, I think every developer would be happy to use it. But when every system call has to be followed by custom code in many cases of a switch(errno) statement, it's just not going to happen (and hasn't happened). Clifford Heath.
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2019-09-09 13:58 +0000 |
| Message-ID | <zUsdF.69191$7O3.2290@fx10.iad> |
| In reply to | #146097 |
Clifford Heath <no.spam@please.net> writes: >On 9/9/19 6:15 am, Ike Naar wrote: >> On 2019-09-07, Clifford Heath <no.spam@please.net> wrote: >>> On the other hand one could augment the existing contract. >>> >>> For example, an ENOSPC error while writing a file can still be set in >>> errno, but a support library could also set an additional variable >>> (error parameter) to the name of the device that is out of space. Even >>> just an fstat() to get the inode details from the fd would be a damn >>> good start. >> >> Is this really necessary? >> If some function, taking a file argument, returs ENOSPC, the caller >> knows the file for which error condition happened, so if the caller >> would be interested in the device, the caller could extract this >> information via other means. > >Yes, it is necessary, both in this case and in other cases, even though >there may be a round-about way of discovering the cause. > >The culture of laziness that engendered this omission is the same Culture of laziness? Guess there's no point in reading further.
[toc] | [prev] | [next] | [standalone]
| From | Jorgen Grahn <grahn+nntp@snipabacken.se> |
|---|---|
| Date | 2019-09-10 14:24 +0000 |
| Message-ID | <slrnqnfch1.cdo.grahn+nntp@frailea.sa.invalid> |
| In reply to | #146097 |
On Sun, 2019-09-08, Clifford Heath wrote:
> On 9/9/19 6:15 am, Ike Naar wrote:
>> On 2019-09-07, Clifford Heath <no.spam@please.net> wrote:
>>> On the other hand one could augment the existing contract.
>>>
>>> For example, an ENOSPC error while writing a file can still be set in
>>> errno, but a support library could also set an additional variable
>>> (error parameter) to the name of the device that is out of space. Even
>>> just an fstat() to get the inode details from the fd would be a damn
>>> good start.
>>
>> Is this really necessary?
>> If some function, taking a file argument, returs ENOSPC, the caller
>> knows the file for which error condition happened, so if the caller
>> would be interested in the device, the caller could extract this
>> information via other means.
>
> Yes, it is necessary, both in this case and in other cases, even though
> there may be a round-about way of discovering the cause.
>
> The culture of laziness that engendered this omission is the same
> culture that results in omission of other detail, caricatured eventually
> by "Unknown Error 0x80000000" type reporting. It's too hard to handle
> every error that might follow from a write() call, so coders end up
> simply saying "Can't save your project" or something even less useful,
> and leaving the end user guessing at why.
>
> Every single error has a concrete context and cause, and we need to make
> a radical commitment to actually reporting the details (all the time but
> most particularly at the operating system level) - as well as the final
> consequences. Failure to properly report details that are available is
> the single thing that most infuriates users, and rightly so.
>
> This is why our users hate us.
I'm not sure if he disagrees or agrees with you, but there's this
essay that's worth reading:
The case for stupid software
Peter da Silva
http://scarydevil.com/~peter/io/stupidsoftware.html
/Jorgen
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
[toc] | [prev] | [next] | [standalone]
| From | Clifford Heath <no.spam@please.net> |
|---|---|
| Date | 2019-09-11 09:22 +1000 |
| Message-ID | <OeWdF.179574$Pr1.166625@fx01.iad> |
| In reply to | #146120 |
On 11/9/19 12:24 am, Jorgen Grahn wrote: > On Sun, 2019-09-08, Clifford Heath wrote: >> On 9/9/19 6:15 am, Ike Naar wrote: >>> On 2019-09-07, Clifford Heath <no.spam@please.net> wrote: >>>> On the other hand one could augment the existing contract. >>>> >>>> For example, an ENOSPC error while writing a file can still be set in >>>> errno, but a support library could also set an additional variable >>>> (error parameter) to the name of the device that is out of space. Even >>>> just an fstat() to get the inode details from the fd would be a damn >>>> good start. >>> >>> Is this really necessary? >>> If some function, taking a file argument, returs ENOSPC, the caller >>> knows the file for which error condition happened, so if the caller >>> would be interested in the device, the caller could extract this >>> information via other means. >> >> Yes, it is necessary, both in this case and in other cases, even though >> there may be a round-about way of discovering the cause. >> >> The culture of laziness that engendered this omission is the same >> culture that results in omission of other detail, caricatured eventually >> by "Unknown Error 0x80000000" type reporting. It's too hard to handle >> every error that might follow from a write() call, so coders end up >> simply saying "Can't save your project" or something even less useful, >> and leaving the end user guessing at why. >> >> Every single error has a concrete context and cause, and we need to make >> a radical commitment to actually reporting the details (all the time but >> most particularly at the operating system level) - as well as the final >> consequences. Failure to properly report details that are available is >> the single thing that most infuriates users, and rightly so. >> >> This is why our users hate us. > > I'm not sure if he disagrees or agrees with you, but there's this > essay that's worth reading: > > The case for stupid software > Peter da Silva > http://scarydevil.com/~peter/io/stupidsoftware.html > > /Jorgen > Thanks. He makes some of the same points - you need to report the original error even if it seems too technical (not report the most likely error instead of the actual error), and you need to point the user to where they can make a configuration change to avoid the error (for example). As I said, it's necessary to indicate Problem/Reason/Solution (in that example, "Login Failed", "Authentication method disallowed", and "Reconfigure your authentication settings"). He claims that proliferation of configuration wizards is the reason for Windows bloat (which I would dispute anyway). In recent Windoze versions everything is comprehensively configurable by powershell/commandline actions that span the entire API for each feature. Microsoft's adoption of this API-oriented system design is admirable and should be followed (even though they also bury the API under mountains of GUIs). They generate all the APIs, command lines and documentation from the single-source design files. This was not the situation in 1999 when the article was written. The reason I chose "ENOSPC" error is that the error occurs on writing a file, but it actually pertains to the volume; and it's a pain to reliably report the volume name given only the file descriptor. So we leave it to the user to guess (with a network drive this can be confusing, too). Clifford Heath.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2019-09-10 16:48 -0700 |
| Message-ID | <03bd835f-4d07-4ad6-ac10-28398177cc66@googlegroups.com> |
| In reply to | #146133 |
On Wednesday, 11 September 2019 00:22:31 UTC+1, Clifford Heath wrote: > The reason I chose "ENOSPC" error is that the error occurs on writing a > file, but it actually pertains to the volume; and it's a pain to > reliably report the volume name given only the file descriptor. So we > leave it to the user to guess (with a network drive this can be > confusing, too). > But as likely as not the error is that the program is stuck in an infinite / size_t == -1 loop writing out bytes to the file. So reporting the volume as full will still be misleading.
[toc] | [prev] | [next] | [standalone]
| From | Clifford Heath <no.spam@please.net> |
|---|---|
| Date | 2019-09-11 10:45 +1000 |
| Message-ID | <usXdF.100047$Ph5.93382@fx27.iad> |
| In reply to | #146134 |
On 11/9/19 9:48 am, Malcolm McLean wrote: > On Wednesday, 11 September 2019 00:22:31 UTC+1, Clifford Heath wrote: > >> The reason I chose "ENOSPC" error is that the error occurs on writing a >> file, but it actually pertains to the volume; and it's a pain to >> reliably report the volume name given only the file descriptor. So we >> leave it to the user to guess (with a network drive this can be >> confusing, too). >> > But as likely as not the error is that the program is stuck in an > infinite / size_t == -1 loop writing out bytes to the file. So > reporting the volume as full will still be misleading. That's one possibility. Another is that *another* process is doing the same on the same volume, possibly even to a file which has no directory entry (no external name, just an open inode) - I've seen this. The operating system can easily know which large files on the full volume have been written to/extended recently, and be able to report them and the name of the process that's writing them (details subject to security, of course). All this stuff is readily available to the O/S, but quite difficult to discover even as a knowledgeable user - so the O/S should provide sufficient diagnostic clues. So your point only reinforces my claim that error context should be gathered and reported from where the error is first detected. Clifford Heath.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-09-06 21:47 +0100 |
| Message-ID | <871rwtxibp.fsf@bsb.me.uk> |
| In reply to | #146080 |
Keith Thompson <kst-u@mib.org> writes: > Ben Bacarisse <ben.usenet@bsb.me.uk> writes: >> Thiago Adams <thiago.adams@gmail.com> writes: >>> On Friday, September 6, 2019 at 3:18:44 PM UTC-3, Keith Thompson wrote: >>>> Thiago Adams writes: >>>> [...] >>>> > I am happy to have found errno_t in the C11 standard. >>>> > I will not change bool for errno_t in my current programs (because >>>> > this creates a inverse logic) but I intend to use errno_t in new >>>> > programs. >>>> >>>> Then your new programs won't compile with implementations that don't >>>> support the optional Annex K (unless you define errno_t yourself). >>> >>> When I compiled using VC++ 2019 I didn't have to add any defines >>> like #define __STDC_WANT_LIB_EXT1__ 1 to use errno_t or other. >>> I guess it is not following the standard in this case. >> >> No, that's permitted. A C11 implementation should not define these >> types etc. when __STDC_WANT_LIB_EXT1__ is defined to be 0 (at the >> appropriate time) and it should when __STDC_WANT_LIB_EXT1__ is defined >> to be 1, but the default (what happens when there is no explicit define >> for __STDC_WANT_LIB_EXT1__) is left up to the implementation. > > Right. There are three ways for an implementation to conform to C11 > with respect to Annex K: > > 1. Don't support it at all. The macro __STDC_LIB_EXT1__ is not > predefined. Defining or undefining __STDC_WANT_LIB_EXT1__ > (probably) has no effect. > > 2. Support it, but disable it by default. __STDC_LIB_EXT1__ is > predefined as 201112L. A program that uses Annex K features > must define __STDC_WANT_LIB_EXT1__ as 1. > > 3. Support it and enable it by default. __STDC_LIB_EXT1__ is > predefined as 201112L. A program that uses Annex K features > may define __STDC_WANT_LIB_EXT1__ as 1. That's clearer because it includes a reminder that the whole of Annex K is optional. <cut> >>> I tried online some compilers and they are not recognizing >>> errno_t even when I use >>> #define __STDC_WANT_LIB_EXT1__ 1 >> >> It would be helpful to see where that define is in your test case, along >> with the compiler's name and the options you used. > > If you're using gcc or clang, that's expected; neither supports Annex K. > (More precisely, the implementations I use, consisting of gcc or clang > with glibc, do not support it. I don't know whether gcc with a > different library implementation might support Annex K.) Ah. For some reason I thought that gcc + recent glibc did, but that was based on zero evidence. Obviously just a wrong thought that somehow got stuck in my head. -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | jadill33@gmail.com |
|---|---|
| Date | 2019-09-05 07:04 -0700 |
| Message-ID | <61b543db-2e2d-4b79-9b41-2ff0dab29a14@googlegroups.com> |
| In reply to | #145998 |
On Wednesday, September 4, 2019 at 5:14:29 PM UTC-4, Thiago Adams wrote:
> In my experience, most of the time I don't need to check
> for specific errors.
>
> For instance, I rarely need to do this:
>
> if (error == specific_error) {
> /*do something*/
> }
>
> in general I just check for general errors:
>
> if (error != error_success) {
> /*do something*/
> }
>
> Some libraries uses 0 to say "no error" and others use
> 1 or true do say "no error".
>
> My suggestion is to add at <errno.h>
>
> typedef int error_t
> and a enum item std_success
>
>
> If you look at existing code, for instance
>
> int thrd_create( thrd_t *thr, thrd_start_t func, void *arg );
> "thrd_success if the creation of the new thread was successful."
>
>
> int bind(SOCKET s, const sockaddr *addr, int namelen);
> "If no error occurs, bind returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be "
>
> You will see different approaches.
>
> But I think it should be more universal and library implementers
> could use the same typedef.
>
> Let's say
>
> error_t MyLibFunc();
>
> then I could use
>
> error_t er = MyLibFunc();
>
> if (er != std_success)
> {
> printf("%s", MyLibErrorToString(er));
> }
>
> and then automatically, the programmer that is using that lib
> knows how do check for errors.
>
>
> What do you think?
> How do you propagate errors? Do you create your own type?
> Do you use enun or int?
> How do you integrate errors from thirty party libs in our own
> errors?
>
>
> Apart of that some range could be reserved for known errors.
> E.g nomen or io errors.
>
> then errors like
>
> thrd_nomem
>
> would not need a specific namespaces.
I think one method is to abstract errors with your own error enumeration
and then translate OS or 3rd party errors to your own enum. Here's a
partial code snippet that demonstrates the strategy. I didn't spend time
to make a standalone code snippet that compiles out of box, but it should
illustrate the idea.
/* The symbol 'error_errno_t_defined' is temporarily used to
record whether or not the 'errno_t' type is available. */
#undef error_errno_t_defined
/*
* If C11 standard support is available, then 'errno_t' is directly
* available, and the declaration of the errno integer type can be
* defined directly in terms of 'errno_t'.
*/
#if defined(__STDC__) && defined(__STDC_VERSION__)
# if (__STDC__ && __STDC_VERSION__ >= 201112L)
typedef errno_t c_errno;
# define error_errno_t_defined
# endif
#endif
/*!
* \brief Define the error number type.
*
* The \c c_errno type represents an integer type meant to store an
* error code native to the local operating system. For example,
* inspecting an error code for an out of memory condition may be
* \c ENOMEM on POSIX systems or \c ERROR_NOT_ENOUGH_MEMORY on
* Windows systems.
*/
#if !defined(error_errno_t_defined)
typedef int c_errno;
#endif
#undef error_errno_t_defined
/*!
* \brief This errno define represents an unknown or untranslatable
* error code.
*
* This error code is defined for Windows errors that do not have a
* corresponding POSIX error code.
*/
#define EOTHER 9999
enum c_error
{
c_error_force_signed__ = -1,
c_success = 0,
c_no_error = 0,
c_argument_list_too_long,
c_argument_out_of_domain,
c_bad_address,
c_bad_file_descriptor,
c_broken_pipe,
c_cross_device_link,
c_device_or_resource_busy,
/*
* 'c_directory_exists' does not have a corresponding POSIX
* errno or Windows GetLastError error code. The concept mirrors
* the same type of error as 'c_file_exists', but is applied
* specifically to directory errors in the 'fileutils.h' library.
*/
c_directory_exists,
c_directory_not_empty,
c_file_exists,
c_file_not_found,
c_file_too_big,
c_filename_too_long,
c_function_not_supported,
c_illegal_seek,
c_insufficient_range,
c_interrupted,
c_invalid_argument,
c_io_error,
c_no_child_process,
c_no_lock_available,
c_no_space_on_device,
c_no_such_device,
c_no_such_file_or_directory,
c_not_a_directory,
c_not_an_executable,
c_not_enough_memory,
c_operation_not_permitted,
c_permission_denied,
c_read_only_file_system,
c_resource_unavailable_try_again,
c_too_many_open_files,
c_other = EOTHER
};
/*! \brief Alias the <tt>enum c_error</tt> type. */
typedef enum c_error c_error;
#if defined(_WIN32) || defined(__WIN32__)
/*!
* \brief Translate a native Windows API error code into the common
* enumeration defined by \c c_error.
* \param wapi_error The Windows API error code.
* \return The corresponding \c c_error value if an error translation
* exists, otherwise \c c_other.
*/
c_error gc_translate_windows_getlasterror( c_errno wapi_error );
#endif
/*!
* \brief Translate a native POSIX API error code into the common
* enumeration defined by \c c_error.
* \param posix_errno The POSIX error code.
* \return The corresponding \c c_error value if an error translation
* exists, otherwise \c c_other.
*/
c_error c_translate_posix_errno( c_errno posix_errno );
static inline c_error c_translate_errno( c_errno e )
{
#if defined(_WIN32) || defined(__WIN32__)
return gc_translate_windows_getlasterror( e );
#else
return c_translate_posix_errno( e );
#endif
}
#if defined(_WIN32) || defined(__WIN32__)
enum c_error gc_translate_windows_getlasterror( c_errno wapi_error )
{
/* Common errors are placed first in the switch to speed up error
code translation. */
switch ( wapi_error )
{
case ERROR_SUCCESS: return c_success;
case ERROR_INVALID_PARAMETER: return c_invalid_argument;
case ERROR_FILE_NOT_FOUND: return c_file_not_found;
case ERROR_PATH_NOT_FOUND: return c_no_such_file_or_directory;
case ERROR_ACCESS_DENIED: return c_permission_denied;
case ERROR_ACCOUNT_DISABLED: return c_permission_denied;
case ERROR_ALREADY_ASSIGNED: return c_device_or_resource_busy;
case ERROR_ALREADY_EXISTS: return c_file_exists;
case ERROR_ARITHMETIC_OVERFLOW: return c_insufficient_range;
case ERROR_BAD_DEVICE: return c_no_such_device;
case ERROR_BAD_EXE_FORMAT: return c_not_an_executable;
case ERROR_BAD_FORMAT: return c_not_an_executable;
case ERROR_BAD_LENGTH: return c_invalid_argument;
case ERROR_BAD_PATHNAME: return c_no_such_file_or_directory;
case ERROR_BAD_PIPE: return c_broken_pipe;
case ERROR_BAD_UNIT: return c_no_such_device;
case ERROR_BROKEN_PIPE: return c_broken_pipe;
case ERROR_BUFFER_OVERFLOW: return c_filename_too_long;
case ERROR_BUSY: return c_device_or_resource_busy;
case ERROR_BUSY_DRIVE: return c_device_or_resource_busy;
case ERROR_CALL_NOT_IMPLEMENTED: return c_function_not_supported;
case ERROR_CANNOT_MAKE: return c_permission_denied;
case ERROR_CANTOPEN: return c_io_error;
case ERROR_CANTREAD: return c_io_error;
case ERROR_CANTWRITE: return c_io_error;
case ERROR_CHILD_NOT_COMPLETE: return c_no_child_process;
case ERROR_CRC: return c_io_error;
case ERROR_CURRENT_DIRECTORY: return c_permission_denied;
case ERROR_DEV_NOT_EXIST: return c_no_such_device;
case ERROR_DEVICE_IN_USE: return c_device_or_resource_busy;
case ERROR_DIR_NOT_EMPTY: return c_directory_not_empty;
case ERROR_DIRECT_ACCESS_HANDLE: return c_bad_file_descriptor;
case ERROR_DIRECTORY: return c_not_a_directory;
case ERROR_DISK_CHANGE: return c_io_error;
case ERROR_DISK_FULL: return c_no_space_on_device;
case ERROR_DRIVE_LOCKED: return c_device_or_resource_busy;
case ERROR_ENVVAR_NOT_FOUND: return c_invalid_argument;
case ERROR_EXE_MARKED_INVALID: return c_not_an_executable;
case ERROR_FILE_EXISTS: return c_file_exists;
case ERROR_FILE_INVALID: return c_no_such_device;
case ERROR_FILENAME_EXCED_RANGE: return c_filename_too_long;
case ERROR_GEN_FAILURE: return c_io_error;
case ERROR_HANDLE_DISK_FULL: return c_no_space_on_device;
case ERROR_INSUFFICIENT_BUFFER: return c_not_enough_memory;
case ERROR_INVALID_ACCESS: return c_permission_denied;
case ERROR_INVALID_ADDRESS: return c_bad_address;
case ERROR_INVALID_DATA: return c_invalid_argument;
case ERROR_INVALID_DRIVE: return c_no_such_device;
case ERROR_INVALID_EXE_SIGNATURE: return c_not_an_executable;
case ERROR_INVALID_FUNCTION: return c_function_not_supported;
case ERROR_INVALID_HANDLE: return c_bad_file_descriptor;
case ERROR_INVALID_NAME: return c_no_such_file_or_directory;
case ERROR_INVALID_TARGET_HANDLE: return c_bad_file_descriptor;
case ERROR_IO_DEVICE: return c_io_error;
case ERROR_LOCK_FAILED: return c_permission_denied;
case ERROR_LOCK_VIOLATION: return c_permission_denied;
case ERROR_LOCKED: return c_device_or_resource_busy;
case ERROR_LOGON_FAILURE: return c_permission_denied;
case ERROR_MAPPED_ALIGNMENT: return c_invalid_argument;
case ERROR_MAX_THRDS_REACHED: return c_resource_unavailable_try_again;
case ERROR_META_EXPANSION_TOO_LONG: return c_argument_list_too_long;
case ERROR_NEGATIVE_SEEK: return c_invalid_argument;
case ERROR_NO_DATA: return c_broken_pipe;
case ERROR_NO_MORE_FILES: return c_no_such_file_or_directory;
case ERROR_NO_MORE_SEARCH_HANDLES: return c_too_many_open_files;
case ERROR_NO_PROC_SLOTS: return c_resource_unavailable_try_again;
case ERROR_NO_SUCH_PRIVILEGE: return c_permission_denied;
case ERROR_NOACCESS: return c_bad_address;
case ERROR_NOT_ENOUGH_MEMORY: return c_not_enough_memory;
case ERROR_NOT_ENOUGH_QUOTA: return c_not_enough_memory;
case ERROR_NOT_READY: return c_resource_unavailable_try_again;
case ERROR_NOT_SAME_DEVICE: return c_cross_device_link;
case ERROR_OPEN_FAILED: return c_io_error;
case ERROR_OPEN_FILES: return c_device_or_resource_busy;
case ERROR_OPERATION_ABORTED: return c_interrupted;
case ERROR_OUTOFMEMORY: return c_not_enough_memory;
case ERROR_PIPE_BUSY: return c_device_or_resource_busy;
case ERROR_PIPE_CONNECTED: return c_device_or_resource_busy;
case ERROR_PIPE_LISTENING: return c_broken_pipe;
case ERROR_PIPE_NOT_CONNECTED: return c_broken_pipe;
case ERROR_READ_FAULT: return c_io_error;
case ERROR_SEEK: return c_io_error;
case ERROR_SEEK_ON_DEVICE: return c_illegal_seek;
case ERROR_SHARING_BUFFER_EXCEEDED: return c_too_many_open_files;
case ERROR_SHARING_VIOLATION: return c_permission_denied;
case ERROR_SIGNAL_PENDING: return c_device_or_resource_busy;
case ERROR_STACK_OVERFLOW: return c_not_enough_memory;
case ERROR_TOO_MANY_MODULES: return c_too_many_open_files;
case ERROR_TOO_MANY_OPEN_FILES: return c_too_many_open_files;
case ERROR_UNRECOGNIZED_VOLUME: return c_no_such_device;
case ERROR_WAIT_NO_CHILDREN: return c_no_child_process;
case ERROR_WRITE_FAULT: return c_io_error;
case ERROR_WRITE_PROTECT: return c_read_only_file_system;
default:
c_unexpected( "unhandled windows api error code" );
break;
}
return c_other;
}
#endif
enum c_error c_translate_posix_errno( c_errno posix_errno )
{
/* Common errors are placed first in the switch to speed up error
code translation. */
switch ( posix_errno )
{
case 0: return c_no_error;
case EINVAL: return c_invalid_argument;
case ENOENT: return c_no_such_file_or_directory; /* ENOFILE */
case EPERM: return c_operation_not_permitted;
case EINTR: return c_interrupted;
case EIO: return c_io_error;
case ENXIO: return c_no_such_device;
case E2BIG: return c_argument_list_too_long;
case ENOEXEC: return c_not_an_executable;
case EBADF: return c_bad_file_descriptor;
case ECHILD: return c_no_child_process;
case EAGAIN: return c_resource_unavailable_try_again;
case ENOMEM: return c_not_enough_memory;
case EACCES: return c_permission_denied;
case EFAULT: return c_bad_address;
case EBUSY: return c_device_or_resource_busy;
case EEXIST: return c_file_exists;
case EXDEV: return c_cross_device_link;
case ENODEV: return c_no_such_device;
case ENOTDIR: return c_not_a_directory;
case EISDIR: return c_io_error;
case ENFILE: return c_too_many_open_files;
case EMFILE: return c_too_many_open_files;
case EFBIG: return c_file_too_big;
case ENOSPC: return c_no_space_on_device;
case ESPIPE: return c_illegal_seek;
case EROFS: return c_read_only_file_system;
case EDOM: return c_argument_out_of_domain;
case ERANGE: return c_insufficient_range;
case ENAMETOOLONG: return c_filename_too_long;
case ENOLCK: return c_no_lock_available;
case ENOSYS: return c_function_not_supported;
case ENOTEMPTY: return c_directory_not_empty;
default:
c_unexpected( "unhandled posix error code" );
break;
}
return c_other;
}
c_errno c_get_native_error( void )
{
#if defined(_WIN32) || defined(__WIN32__)
return GetLastError();
#else
return errno;
#endif
}
enum c_error c_get_error( void )
{
#if defined(_WIN32) || defined(__WIN32__)
return gc_translate_windows_getlasterror( GetLastError() );
#else
return c_translate_posix_errno( errno )
#endif
}
You can also provide a lookup table of error strings and you can normalize
the error messages of OS specific errors to your liking.
Third party libraries are just an extension of this. You usually have
one function to get the native error code, and define one function that
translates API errors into your common error code. You have to provide
the mapping yourself. A simple example would be OpenGL error codes and
the glGetError command.
I crafted this because of my desire to support an abstraction of specific
POSIX and Windows features in a cross platform library. A word of caution
though, making a common list of all errors from an arbitrary list of 3rd
party libraries can be problematic and a maintenance hassle if you need
to support multiple versions of the same API. YMMV.
Best regards,
John D.
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2019-09-05 07:36 -0700 |
| Message-ID | <3936f028-3dca-47c5-a424-e6218a435068@googlegroups.com> |
| In reply to | #146025 |
On Thursday, September 5, 2019 at 11:04:40 AM UTC-3, jadi...@gmail.com wrote:
> On Wednesday, September 4, 2019 at 5:14:29 PM UTC-4, Thiago Adams wrote:
> > In my experience, most of the time I don't need to check
> > for specific errors.
> >
> > For instance, I rarely need to do this:
> >
> > if (error == specific_error) {
> > /*do something*/
> > }
> >
> > in general I just check for general errors:
> >
> > if (error != error_success) {
> > /*do something*/
> > }
> >
> > Some libraries uses 0 to say "no error" and others use
> > 1 or true do say "no error".
> >
> > My suggestion is to add at <errno.h>
> >
> > typedef int error_t
> > and a enum item std_success
> >
> >
> > If you look at existing code, for instance
> >
> > int thrd_create( thrd_t *thr, thrd_start_t func, void *arg );
> > "thrd_success if the creation of the new thread was successful."
> >
> >
> > int bind(SOCKET s, const sockaddr *addr, int namelen);
> > "If no error occurs, bind returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be "
> >
> > You will see different approaches.
> >
> > But I think it should be more universal and library implementers
> > could use the same typedef.
> >
> > Let's say
> >
> > error_t MyLibFunc();
> >
> > then I could use
> >
> > error_t er = MyLibFunc();
> >
> > if (er != std_success)
> > {
> > printf("%s", MyLibErrorToString(er));
> > }
> >
> > and then automatically, the programmer that is using that lib
> > knows how do check for errors.
> >
> >
> > What do you think?
> > How do you propagate errors? Do you create your own type?
> > Do you use enun or int?
> > How do you integrate errors from thirty party libs in our own
> > errors?
> >
> >
> > Apart of that some range could be reserved for known errors.
> > E.g nomen or io errors.
> >
> > then errors like
> >
> > thrd_nomem
> >
> > would not need a specific namespaces.
>
> I think one method is to abstract errors with your own error enumeration
> and then translate OS or 3rd party errors to your own enum. Here's a
> partial code snippet that demonstrates the strategy. I didn't spend time
> to make a standalone code snippet that compiles out of box, but it should
> illustrate the idea.
>
> /* The symbol 'error_errno_t_defined' is temporarily used to
> record whether or not the 'errno_t' type is available. */
> #undef error_errno_t_defined
>
> /*
> * If C11 standard support is available, then 'errno_t' is directly
> * available, and the declaration of the errno integer type can be
> * defined directly in terms of 'errno_t'.
> */
> #if defined(__STDC__) && defined(__STDC_VERSION__)
> # if (__STDC__ && __STDC_VERSION__ >= 201112L)
> typedef errno_t c_errno;
> # define error_errno_t_defined
> # endif
> #endif
>
> /*!
> * \brief Define the error number type.
> *
> * The \c c_errno type represents an integer type meant to store an
> * error code native to the local operating system. For example,
> * inspecting an error code for an out of memory condition may be
> * \c ENOMEM on POSIX systems or \c ERROR_NOT_ENOUGH_MEMORY on
> * Windows systems.
> */
> #if !defined(error_errno_t_defined)
> typedef int c_errno;
> #endif
>
> #undef error_errno_t_defined
>
> /*!
> * \brief This errno define represents an unknown or untranslatable
> * error code.
> *
> * This error code is defined for Windows errors that do not have a
> * corresponding POSIX error code.
> */
> #define EOTHER 9999
>
> enum c_error
> {
> c_error_force_signed__ = -1,
>
> c_success = 0,
> c_no_error = 0,
>
> c_argument_list_too_long,
> c_argument_out_of_domain,
> c_bad_address,
> c_bad_file_descriptor,
> c_broken_pipe,
> c_cross_device_link,
> c_device_or_resource_busy,
>
> /*
> * 'c_directory_exists' does not have a corresponding POSIX
> * errno or Windows GetLastError error code. The concept mirrors
> * the same type of error as 'c_file_exists', but is applied
> * specifically to directory errors in the 'fileutils.h' library.
> */
> c_directory_exists,
>
> c_directory_not_empty,
> c_file_exists,
> c_file_not_found,
> c_file_too_big,
> c_filename_too_long,
> c_function_not_supported,
> c_illegal_seek,
> c_insufficient_range,
> c_interrupted,
> c_invalid_argument,
> c_io_error,
> c_no_child_process,
> c_no_lock_available,
> c_no_space_on_device,
> c_no_such_device,
> c_no_such_file_or_directory,
> c_not_a_directory,
> c_not_an_executable,
> c_not_enough_memory,
> c_operation_not_permitted,
> c_permission_denied,
> c_read_only_file_system,
> c_resource_unavailable_try_again,
> c_too_many_open_files,
>
> c_other = EOTHER
> };
>
> /*! \brief Alias the <tt>enum c_error</tt> type. */
> typedef enum c_error c_error;
>
> #if defined(_WIN32) || defined(__WIN32__)
> /*!
> * \brief Translate a native Windows API error code into the common
> * enumeration defined by \c c_error.
> * \param wapi_error The Windows API error code.
> * \return The corresponding \c c_error value if an error translation
> * exists, otherwise \c c_other.
> */
> c_error gc_translate_windows_getlasterror( c_errno wapi_error );
> #endif
>
> /*!
> * \brief Translate a native POSIX API error code into the common
> * enumeration defined by \c c_error.
> * \param posix_errno The POSIX error code.
> * \return The corresponding \c c_error value if an error translation
> * exists, otherwise \c c_other.
> */
> c_error c_translate_posix_errno( c_errno posix_errno );
>
> static inline c_error c_translate_errno( c_errno e )
> {
> #if defined(_WIN32) || defined(__WIN32__)
> return gc_translate_windows_getlasterror( e );
> #else
> return c_translate_posix_errno( e );
> #endif
> }
>
> #if defined(_WIN32) || defined(__WIN32__)
> enum c_error gc_translate_windows_getlasterror( c_errno wapi_error )
> {
> /* Common errors are placed first in the switch to speed up error
> code translation. */
> switch ( wapi_error )
> {
> case ERROR_SUCCESS: return c_success;
> case ERROR_INVALID_PARAMETER: return c_invalid_argument;
> case ERROR_FILE_NOT_FOUND: return c_file_not_found;
> case ERROR_PATH_NOT_FOUND: return c_no_such_file_or_directory;
>
> case ERROR_ACCESS_DENIED: return c_permission_denied;
> case ERROR_ACCOUNT_DISABLED: return c_permission_denied;
> case ERROR_ALREADY_ASSIGNED: return c_device_or_resource_busy;
> case ERROR_ALREADY_EXISTS: return c_file_exists;
> case ERROR_ARITHMETIC_OVERFLOW: return c_insufficient_range;
> case ERROR_BAD_DEVICE: return c_no_such_device;
> case ERROR_BAD_EXE_FORMAT: return c_not_an_executable;
> case ERROR_BAD_FORMAT: return c_not_an_executable;
> case ERROR_BAD_LENGTH: return c_invalid_argument;
> case ERROR_BAD_PATHNAME: return c_no_such_file_or_directory;
> case ERROR_BAD_PIPE: return c_broken_pipe;
> case ERROR_BAD_UNIT: return c_no_such_device;
> case ERROR_BROKEN_PIPE: return c_broken_pipe;
> case ERROR_BUFFER_OVERFLOW: return c_filename_too_long;
> case ERROR_BUSY: return c_device_or_resource_busy;
> case ERROR_BUSY_DRIVE: return c_device_or_resource_busy;
> case ERROR_CALL_NOT_IMPLEMENTED: return c_function_not_supported;
> case ERROR_CANNOT_MAKE: return c_permission_denied;
> case ERROR_CANTOPEN: return c_io_error;
> case ERROR_CANTREAD: return c_io_error;
> case ERROR_CANTWRITE: return c_io_error;
> case ERROR_CHILD_NOT_COMPLETE: return c_no_child_process;
> case ERROR_CRC: return c_io_error;
> case ERROR_CURRENT_DIRECTORY: return c_permission_denied;
> case ERROR_DEV_NOT_EXIST: return c_no_such_device;
> case ERROR_DEVICE_IN_USE: return c_device_or_resource_busy;
> case ERROR_DIR_NOT_EMPTY: return c_directory_not_empty;
> case ERROR_DIRECT_ACCESS_HANDLE: return c_bad_file_descriptor;
> case ERROR_DIRECTORY: return c_not_a_directory;
> case ERROR_DISK_CHANGE: return c_io_error;
> case ERROR_DISK_FULL: return c_no_space_on_device;
> case ERROR_DRIVE_LOCKED: return c_device_or_resource_busy;
> case ERROR_ENVVAR_NOT_FOUND: return c_invalid_argument;
> case ERROR_EXE_MARKED_INVALID: return c_not_an_executable;
> case ERROR_FILE_EXISTS: return c_file_exists;
> case ERROR_FILE_INVALID: return c_no_such_device;
> case ERROR_FILENAME_EXCED_RANGE: return c_filename_too_long;
> case ERROR_GEN_FAILURE: return c_io_error;
> case ERROR_HANDLE_DISK_FULL: return c_no_space_on_device;
> case ERROR_INSUFFICIENT_BUFFER: return c_not_enough_memory;
> case ERROR_INVALID_ACCESS: return c_permission_denied;
> case ERROR_INVALID_ADDRESS: return c_bad_address;
> case ERROR_INVALID_DATA: return c_invalid_argument;
> case ERROR_INVALID_DRIVE: return c_no_such_device;
> case ERROR_INVALID_EXE_SIGNATURE: return c_not_an_executable;
> case ERROR_INVALID_FUNCTION: return c_function_not_supported;
> case ERROR_INVALID_HANDLE: return c_bad_file_descriptor;
> case ERROR_INVALID_NAME: return c_no_such_file_or_directory;
> case ERROR_INVALID_TARGET_HANDLE: return c_bad_file_descriptor;
> case ERROR_IO_DEVICE: return c_io_error;
> case ERROR_LOCK_FAILED: return c_permission_denied;
> case ERROR_LOCK_VIOLATION: return c_permission_denied;
> case ERROR_LOCKED: return c_device_or_resource_busy;
> case ERROR_LOGON_FAILURE: return c_permission_denied;
> case ERROR_MAPPED_ALIGNMENT: return c_invalid_argument;
> case ERROR_MAX_THRDS_REACHED: return c_resource_unavailable_try_again;
> case ERROR_META_EXPANSION_TOO_LONG: return c_argument_list_too_long;
> case ERROR_NEGATIVE_SEEK: return c_invalid_argument;
> case ERROR_NO_DATA: return c_broken_pipe;
> case ERROR_NO_MORE_FILES: return c_no_such_file_or_directory;
> case ERROR_NO_MORE_SEARCH_HANDLES: return c_too_many_open_files;
> case ERROR_NO_PROC_SLOTS: return c_resource_unavailable_try_again;
> case ERROR_NO_SUCH_PRIVILEGE: return c_permission_denied;
> case ERROR_NOACCESS: return c_bad_address;
> case ERROR_NOT_ENOUGH_MEMORY: return c_not_enough_memory;
> case ERROR_NOT_ENOUGH_QUOTA: return c_not_enough_memory;
> case ERROR_NOT_READY: return c_resource_unavailable_try_again;
> case ERROR_NOT_SAME_DEVICE: return c_cross_device_link;
> case ERROR_OPEN_FAILED: return c_io_error;
> case ERROR_OPEN_FILES: return c_device_or_resource_busy;
> case ERROR_OPERATION_ABORTED: return c_interrupted;
> case ERROR_OUTOFMEMORY: return c_not_enough_memory;
> case ERROR_PIPE_BUSY: return c_device_or_resource_busy;
> case ERROR_PIPE_CONNECTED: return c_device_or_resource_busy;
> case ERROR_PIPE_LISTENING: return c_broken_pipe;
> case ERROR_PIPE_NOT_CONNECTED: return c_broken_pipe;
> case ERROR_READ_FAULT: return c_io_error;
> case ERROR_SEEK: return c_io_error;
> case ERROR_SEEK_ON_DEVICE: return c_illegal_seek;
> case ERROR_SHARING_BUFFER_EXCEEDED: return c_too_many_open_files;
> case ERROR_SHARING_VIOLATION: return c_permission_denied;
> case ERROR_SIGNAL_PENDING: return c_device_or_resource_busy;
> case ERROR_STACK_OVERFLOW: return c_not_enough_memory;
> case ERROR_TOO_MANY_MODULES: return c_too_many_open_files;
> case ERROR_TOO_MANY_OPEN_FILES: return c_too_many_open_files;
> case ERROR_UNRECOGNIZED_VOLUME: return c_no_such_device;
> case ERROR_WAIT_NO_CHILDREN: return c_no_child_process;
> case ERROR_WRITE_FAULT: return c_io_error;
> case ERROR_WRITE_PROTECT: return c_read_only_file_system;
>
> default:
> c_unexpected( "unhandled windows api error code" );
> break;
> }
>
> return c_other;
> }
> #endif
>
> enum c_error c_translate_posix_errno( c_errno posix_errno )
> {
> /* Common errors are placed first in the switch to speed up error
> code translation. */
> switch ( posix_errno )
> {
> case 0: return c_no_error;
> case EINVAL: return c_invalid_argument;
> case ENOENT: return c_no_such_file_or_directory; /* ENOFILE */
>
> case EPERM: return c_operation_not_permitted;
> case EINTR: return c_interrupted;
> case EIO: return c_io_error;
> case ENXIO: return c_no_such_device;
> case E2BIG: return c_argument_list_too_long;
> case ENOEXEC: return c_not_an_executable;
> case EBADF: return c_bad_file_descriptor;
> case ECHILD: return c_no_child_process;
> case EAGAIN: return c_resource_unavailable_try_again;
> case ENOMEM: return c_not_enough_memory;
> case EACCES: return c_permission_denied;
> case EFAULT: return c_bad_address;
> case EBUSY: return c_device_or_resource_busy;
> case EEXIST: return c_file_exists;
> case EXDEV: return c_cross_device_link;
> case ENODEV: return c_no_such_device;
> case ENOTDIR: return c_not_a_directory;
> case EISDIR: return c_io_error;
> case ENFILE: return c_too_many_open_files;
> case EMFILE: return c_too_many_open_files;
> case EFBIG: return c_file_too_big;
> case ENOSPC: return c_no_space_on_device;
> case ESPIPE: return c_illegal_seek;
> case EROFS: return c_read_only_file_system;
> case EDOM: return c_argument_out_of_domain;
> case ERANGE: return c_insufficient_range;
> case ENAMETOOLONG: return c_filename_too_long;
> case ENOLCK: return c_no_lock_available;
> case ENOSYS: return c_function_not_supported;
> case ENOTEMPTY: return c_directory_not_empty;
>
> default:
> c_unexpected( "unhandled posix error code" );
> break;
> }
>
> return c_other;
> }
>
> c_errno c_get_native_error( void )
> {
> #if defined(_WIN32) || defined(__WIN32__)
> return GetLastError();
> #else
> return errno;
> #endif
> }
>
> enum c_error c_get_error( void )
> {
> #if defined(_WIN32) || defined(__WIN32__)
> return gc_translate_windows_getlasterror( GetLastError() );
> #else
> return c_translate_posix_errno( errno )
> #endif
> }
>
> You can also provide a lookup table of error strings and you can normalize
> the error messages of OS specific errors to your liking.
>
> Third party libraries are just an extension of this. You usually have
> one function to get the native error code, and define one function that
> translates API errors into your common error code. You have to provide
> the mapping yourself. A simple example would be OpenGL error codes and
> the glGetError command.
>
> I crafted this because of my desire to support an abstraction of specific
> POSIX and Windows features in a cross platform library. A word of caution
> though, making a common list of all errors from an arbitrary list of 3rd
> party libraries can be problematic and a maintenance hassle if you need
> to support multiple versions of the same API. YMMV.
>
> Best regards,
> John D.
Very interesting.
But considering Windows is already mapping some erros to POSIX
what do you think is just convert windows errors to POSIX instead a
new value?
I would like to have a lib for sockets that is the same for windows
and linux. I think windows sockets errors already have POSIX values
but the have their own defines. 100+POSIX
For instance EACCES = 13
and
WSAEACCES = 10013
The disadvantage in to use the windows -> posix conversion is when
you have some error that is not present. Creating a new type you can
add the union set .
[toc] | [prev] | [next] | [standalone]
| From | jadill33@gmail.com |
|---|---|
| Date | 2019-09-05 08:43 -0700 |
| Message-ID | <a55d6642-8162-4301-83db-706099134f88@googlegroups.com> |
| In reply to | #146030 |
On Thursday, September 5, 2019 at 10:36:47 AM UTC-4, Thiago Adams wrote:
> On Thursday, September 5, 2019 at 11:04:40 AM UTC-3, jadi...@gmail.com wrote:
> > On Wednesday, September 4, 2019 at 5:14:29 PM UTC-4, Thiago Adams wrote:
> > > In my experience, most of the time I don't need to check
> > > for specific errors.
> > >
> > > For instance, I rarely need to do this:
> > >
> > > if (error == specific_error) {
> > > /*do something*/
> > > }
> > >
> > > in general I just check for general errors:
> > >
> > > if (error != error_success) {
> > > /*do something*/
> > > }
> > >
> > > Some libraries uses 0 to say "no error" and others use
> > > 1 or true do say "no error".
> > >
> > > My suggestion is to add at <errno.h>
> > >
> > > typedef int error_t
> > > and a enum item std_success
> > >
> > >
> > > If you look at existing code, for instance
> > >
> > > int thrd_create( thrd_t *thr, thrd_start_t func, void *arg );
> > > "thrd_success if the creation of the new thread was successful."
> > >
> > >
> > > int bind(SOCKET s, const sockaddr *addr, int namelen);
> > > "If no error occurs, bind returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be "
> > >
> > > You will see different approaches.
> > >
> > > But I think it should be more universal and library implementers
> > > could use the same typedef.
> > >
> > > Let's say
> > >
> > > error_t MyLibFunc();
> > >
> > > then I could use
> > >
> > > error_t er = MyLibFunc();
> > >
> > > if (er != std_success)
> > > {
> > > printf("%s", MyLibErrorToString(er));
> > > }
> > >
> > > and then automatically, the programmer that is using that lib
> > > knows how do check for errors.
> > >
> > >
> > > What do you think?
> > > How do you propagate errors? Do you create your own type?
> > > Do you use enun or int?
> > > How do you integrate errors from thirty party libs in our own
> > > errors?
> > >
> > >
> > > Apart of that some range could be reserved for known errors.
> > > E.g nomen or io errors.
> > >
> > > then errors like
> > >
> > > thrd_nomem
> > >
> > > would not need a specific namespaces.
> >
> > I think one method is to abstract errors with your own error enumeration
> > and then translate OS or 3rd party errors to your own enum. Here's a
> > partial code snippet that demonstrates the strategy. I didn't spend time
> > to make a standalone code snippet that compiles out of box, but it should
> > illustrate the idea.
> >
<snip>
> >
> > You can also provide a lookup table of error strings and you can normalize
> > the error messages of OS specific errors to your liking.
> >
> > Third party libraries are just an extension of this. You usually have
> > one function to get the native error code, and define one function that
> > translates API errors into your common error code. You have to provide
> > the mapping yourself. A simple example would be OpenGL error codes and
> > the glGetError command.
> >
> > I crafted this because of my desire to support an abstraction of specific
> > POSIX and Windows features in a cross platform library. A word of caution
> > though, making a common list of all errors from an arbitrary list of 3rd
> > party libraries can be problematic and a maintenance hassle if you need
> > to support multiple versions of the same API. YMMV.
> >
>
> Very interesting.
> But considering Windows is already mapping some erros to POSIX
> what do you think is just convert windows errors to POSIX instead a
> new value?
>
> I would like to have a lib for sockets that is the same for windows
> and linux. I think windows sockets errors already have POSIX values
> but the have their own defines. 100+POSIX
>
> For instance EACCES = 13
> and
> WSAEACCES = 10013
>
> The disadvantage in to use the windows -> posix conversion is when
> you have some error that is not present. Creating a new type you can
> add the union set.
Yes, the advantage of your own enumeration type is you can combine unique
error codes from each API into a single list, if you need that level of
granularity. You can still use c_translate_posix_errno on Windows (I use
the 'gc' as a kind of internal namespace for my library), and it will provide
whatever Windows deems its subset of POSIX error codes.
In the library, I made a decision to use the Windows API when detected to
get "as close to the source" as possible. There are several POSIX errors
that Windows ignores or fails to translate to. For example, an action using
the Windows API would cause an errno that would translate to one vague
POSIX value that didn't make a whole lot of sense, but GetLastError would
reveal something that made more sense. So I made my own mapping based on
reading the descriptions of all the errors from GetLastError.
I'm sure experts could find issues with how I mapped error codes, but it's
simplified my error handling within my library wrapper of API features.
Best regards,
John D.
[toc] | [prev] | [standalone]
Page 3 of 3 — ← Prev page 1 2 [3]
Back to top | Article view | comp.lang.c
csiph-web