Am 08.06.2025 um 10:55 schrieb Muttley@DastardlyHQ.org:
You can of course use setjmp & longjmp in C but depending on how many levels >> up you jump they could be more trouble than they're worth. I think I've only >> ever used them once.
That's makes a lot of work and it's really ugly. And you need global >jump_buf-s for that.
Context, in the general case, matters. ...
It's been decades that I used C++, but back then in the 1990's
we did pass error context with the thrown error object.
That's an inherent part of C++'s exception handling. If you useMost exceptions you throw or catch are bad_allocs or system_errors.
standard error classes without context that's of course possible,
but nothing prevents you to define yet another error class derived
from some existing error class with additional information. You
are actually free to do what suits you and your projects best;
use rudimentary handling, or have a sophisticated error framework,
or anything in between.
Its no different to C++ exceptions except obviously no destructors
are called so there's no chance to do a tidy up at each stack level.
Am 08.06.2025 um 16:52 schrieb wij:My primary interest of programming is on the theory. From your presented wording, I don't think you can conduct a logical discussion (it seems you continue to ask for logical proof).
I know a bit of the development of std::filesystem. The view of mere 'standard'
disregards fact and uses more the 'assertion' criticized.
Another statement without arguments.
It seems your whole idea (and 'fact') is based on C++'s propaganda."dont' need" is illusion, errors are always there, mostly ignored and encouraged
to ignore by simplification.
If the code is written to be exception-safe, i.e. it uses
RAII throughout, then this is easily possible.
C has not hard coded what 'exception' should be. E.g. C can also set an error
object and let interested code to handle it in many ways, what's left is impl.
issues.
Are you serious? The fact that the exception type is transported along
with the exception itself makes things really convenient. This way, the
stack can be unrolled until the correct exception handler is found.
But, I think the 'throw' mechanism (not std::exception) is good, like many others. 'throw' is more like a soft assert failure, which is no error handling.
Totally different - asserts are handled at debug-time.
Based on this statement, you didn't understand exceptions correctly.
On Sun, 8 Jun 2025 17:02:08 +0200
Bonita Montero <Bonita.Montero@gmail.com> wibbled:
Am 08.06.2025 um 10:55 schrieb Muttley@DastardlyHQ.org:
You can of course use setjmp & longjmp in C but depending on how many levels
up you jump they could be more trouble than they're worth. I think I've only
ever used them once.
That's makes a lot of work and it's really ugly. And you need global >>jump_buf-s for that.
Its no different to C++ exceptions except obviously no destructors are called >so there's no chance to do a tidy up at each stack level. Also jumps arn't >limited to lower to higher stack frames jumps, they can jump about all over >the place. Whether thats useful or not I can't say. I've never needed it.
Am 07.06.2025 um 23:12 schrieb Janis Papanagnou:
Context, in the general case, matters. ...
If you need the context then you catch the exception near where
it is thrown; but that's not usual, meaning in most cases you
don't need that context. F.e. when a bad_alloc is thown it dosn't
matter which allocation failed, it's just enough to know that a >memory-collapse happened.
Muttley@DastardlyHQ.org writes:
On Sun, 8 Jun 2025 17:02:08 +0200
Bonita Montero <Bonita.Montero@gmail.com> wibbled:
Am 08.06.2025 um 10:55 schrieb Muttley@DastardlyHQ.org:
You can of course use setjmp & longjmp in C but depending on how many levels
up you jump they could be more trouble than they're worth. I think I've only
ever used them once.
That's makes a lot of work and it's really ugly. And you need global >>>jump_buf-s for that.
Its no different to C++ exceptions except obviously no destructors are called >>so there's no chance to do a tidy up at each stack level. Also jumps arn't >>limited to lower to higher stack frames jumps, they can jump about all over >>the place. Whether thats useful or not I can't say. I've never needed it.
I've used sigsetjmp/siglongjmp in C++ code, very successfully. As an experiment a few
years ago, I replaced it with C++ exceptions and took a 20% performance
hit in the application. Needless to say the experiment was a failure.
In general, I tend to concur with wij - I prefer to handle run-of-the-mill errors when they're detected.
For example:^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
c_file_card_unit::c_file_card_unit(ulong channel, ulong unit, const char *name,
So, if is_ready() returns false after the constructor runs,
the creator of the object knows the creation failed.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 07.06.2025 um 23:12 schrieb Janis Papanagnou:
Context, in the general case, matters. ...
If you need the context then you catch the exception near where
it is thrown; but that's not usual, meaning in most cases you
don't need that context. F.e. when a bad_alloc is thown it dosn't
matter which allocation failed, it's just enough to know that a
memory-collapse happened.
Actually it very much matters where the allocation failed, if
one wishes to recover from it.
It seems your concept of error
handling is simply reporting it (hopefully with sufficient
context information for the user to understand what needs to
be fixed) and calling exit().
My primary interest of programming is on the theory. ...
I've used sigsetjmp/siglongjmp in C++ code, very successfully. As an experiment a few
years ago, I replaced it with C++ exceptions and took a 20% performance
hit in the application. Needless to say the experiment was a failure.
Actually it very much matters where the allocation failed, if
one wishes to recover from it.
Am 08.06.2025 um 18:28 schrieb wij:Where did I talk about theory?
My primary interest of programming is on the theory. ...
Then don't talk about practical issues.
For example:
c_file_card_unit::c_file_card_unit(ulong channel, ulong unit, const char *name,
c_logger *lp, c_card_dlp *dlp, bool punch,
bool hollerith, const char *binpath)
: c_card_unit(channel, unit, lp, dlp, punch)
{
int flags = punch?O_RDWR|O_APPEND:O_RDONLY;
int diag;
uint8 header[CARD_SIZE_COLUMNS];
f_file = NULL;
f_inputhopper = 0ul;
f_binfd = -1;
snprintf(f_binary_path, sizeof(f_binary_path), "%s", binpath);
diag = stat(name, &cu_stat);
if (diag == -1) {
if ((errno == ENOENT) && punch) {
flags |= O_CREAT|O_EXCL;
}
}
cu_fd = open(name, flags, 0600);
if (cu_fd == -1) {
fprintf(stdout, "%4.4lu/%2.2lu Unable to open '%s': %s\n", cu_channel, cu_unit, name, strerror(errno)); return;
}
diag = fcntl(cu_fd, F_SETFD, FD_CLOEXEC);
if (diag == -1) {
lp->log("%4.4lu/%2.2lu Unable to set FD_CLOEXEC on '%s': %s\n",
cu_channel, cu_unit, name, strerror(errno));
diag = close(cu_fd);
cu_fd = -1;
return;
}
...
}
bool
c_file_card_unit::is_ready(void)
{
return (cu_fd != -1) && ((f_file != NULL) && !feof(f_file));
}
So, if is_ready() returns false after the constructor runs,
the creator of the object knows the creation failed.
In C every call level has to deal with erorrs, whereas in C++ only
one level at the upper edge has to catch the errors.
Am 08.06.2025 um 17:08 schrieb Muttley@DastardlyHQ.org:
Its no different to C++ exceptions except obviously no destructors
are called so there's no chance to do a tidy up at each stack level.
It's much more complicated than exceptions because the functions where
the error raises and where the error is "caught" need shared global >variables. C++ doesn't need that, just throw and catch and everything
is glued to the runtime.
And the problem with your solution is: All functions between the setjmp-
and the longjmp-calls don't have any cleanup, i.e. they don't handle
back their opened resources to the runtime or the kernel. With RAII in >combination with exceptions that's for free.
Do you really think setjmp() / longjmp() is a competitive solution ?
You're naive.
In general, I tend to concur with wij - I prefer to handle run-of-the-mill >errors when they're detected.
Did you actually read what I wrote? Obviously in C++ you'd use exceptionsI ask myself if setjmp() / longjmp() with manual unwinding then is
but in C without any kind of built in exception mechanism they're better
than nothing if you want to jump out of a deep stack.
Same here. I think with exceptions the clue is in the name. They should really
only be used for exceptional circumstances, not as a general minor error handling mechanism.
Not necessarily that simple. It might be easier if C++ had
try/finally (like Python does), but it doesn’t.
Am 08.06.2025 um 18:58 schrieb Scott Lurndal:
Actually it very much matters where the allocation failed, if
one wishes to recover from it.
This very rarely makes sense. It's almost always the case that if
an operation fails, it doesn't matter what allocation was behind
it.
Have you ever written real-world production code? Like an operating system, where allocation failures should -never- result in an
inability to recover.
Am 09.06.2025 um 16:01 schrieb Scott Lurndal:
Have you ever written real-world production code? Like an operating
system, where allocation failures should -never- result in an
inability to recover.
If you need an allocation to proceed and it fails you can't recover.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 09.06.2025 um 16:01 schrieb Scott Lurndal:
Have you ever written real-world production code? Like an operating
system, where allocation failures should -never- result in an
inability to recover.
If you need an allocation to proceed and it fails you can't recover.
That's your problem caused by poor design and implementation.
Exacerbated by the propensity for you to use C++ features that require dynamic allocation where other forms of data structures are more suitable.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 09.06.2025 um 16:01 schrieb Scott Lurndal:
Have you ever written real-world production code? Like an operating
system, where allocation failures should -never- result in an
inability to recover.
If you need an allocation to proceed and it fails you can't recover.
That's your problem caused by poor design and implementation.
Am 09.06.2025 um 17:53 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 09.06.2025 um 16:01 schrieb Scott Lurndal:
Have you ever written real-world production code? Like an operating >>>> system, where allocation failures should -never- result in an
inability to recover.
If you need an allocation to proceed and it fails you can't recover.
That's your problem caused by poor design and implementation.
That's how 100% of all programs that deal with bad_alloc are designed.
Exacerbated by the propensity for you to use C++ features that require
dynamic allocation where other forms of data structures are more suitable.
When dynamic allocation is needed it is needed.
And there are many ways to handle it that don't include throwing
bad_alloc when the system is unable to provide additional address
space, memory or backing store.
Allocating major data structures at application start (perhaps using
a pool allocator) and crafting your algorithms such that they
don't require infinite memory is a good start.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 08.06.2025 um 18:58 schrieb Scott Lurndal:
Actually it very much matters where the allocation failed, if
one wishes to recover from it.
This very rarely makes sense. It's almost always the case that if
an operation fails, it doesn't matter what allocation was behind
it.
Have you ever written real-world production code? Like an operating system, where allocation failures should -never- result in an
inability to recover.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 09.06.2025 um 17:53 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 09.06.2025 um 16:01 schrieb Scott Lurndal:
Have you ever written real-world production code? Like an operating >>>>> system, where allocation failures should -never- result in an
inability to recover.
If you need an allocation to proceed and it fails you can't recover.
That's your problem caused by poor design and implementation.
That's how 100% of all programs that deal with bad_alloc are designed.
Exacerbated by the propensity for you to use C++ features that requireWhen dynamic allocation is needed it is needed.
dynamic allocation where other forms of data structures are more suitable. >>
And there are many ways to handle it that don't include throwing
bad_alloc when the system is unable to provide additional address
space, memory or backing store.
Allocating major data structures at application start (perhaps using a
pool allocator) and crafting your algorithms such that they
don't require infinite memory is a good start.
You're talking to someone who can't understand the difference
between comp.lang.c and comp.lang.c++. What do you expect?
On 2025-06-08, Scott Lurndal <scott@slp53.sl.home> wrote:
Muttley@DastardlyHQ.org writes:
On Sun, 8 Jun 2025 17:02:08 +0200
Bonita Montero <Bonita.Montero@gmail.com> wibbled:
Am 08.06.2025 um 10:55 schrieb Muttley@DastardlyHQ.org:
You can of course use setjmp & longjmp in C but depending on how
many levels up you jump they could be more trouble than they're
worth. I think I've only ever used them once.
That's makes a lot of work and it's really ugly. And you need
global jump_buf-s for that.
setjmp and longjmp have a clearly defined implementation model
(obviously not in ISO C, but so in implementation practice).
On Mon, 2 Jun 2025 09:35:24 +0200, Bonita Montero wrote:
Am 01.06.2025 um 09:43 schrieb Lawrence D'Oliveiro:
On Sun, 1 Jun 2025 07:58:54 +0200, Bonita Montero wrote:
Sth. like this:
for( directory_entry const &de : recursive_directory_iterator( "\\", >>>> directory_options::follow_directory_symlink ) )
cout << de.path() << endl;
You need the dirfd functions to avoid certain potential security
holes on operations with symlinks.
Which security holes ?
TOCTOU.
On Mon, 09 Jun 2025 18:33:38 GMT
scott@slp53.sl.home (Scott Lurndal) wibbled:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 09.06.2025 um 17:53 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 09.06.2025 um 16:01 schrieb Scott Lurndal:
Have you ever written real-world production code? Like an operating >>>>>> system, where allocation failures should -never- result in an
inability to recover.
If you need an allocation to proceed and it fails you can't recover.
That's your problem caused by poor design and implementation.
That's how 100% of all programs that deal with bad_alloc are designed.
Exacerbated by the propensity for you to use C++ features that require >>>> dynamic allocation where other forms of data structures are more suitable. >>>When dynamic allocation is needed it is needed.
And there are many ways to handle it that don't include throwing
bad_alloc when the system is unable to provide additional address
space, memory or backing store.
Allocating major data structures at application start (perhaps using a
pool allocator) and crafting your algorithms such that they
don't require infinite memory is a good start.
Ugh. Then you end up like the Java JVM - grabbing boatloads of memory that >causes huge startup delays and can often cause the machine to do lots of >swapping and/or slow everything else down to treacle.
And all the existing C compilers in the entire planet support
the C90 dialect[*], if so instructed. Where is the problem?
Am 03.06.2025 um 02:37 schrieb Lawrence D'Oliveiro:
On Mon, 2 Jun 2025 09:35:24 +0200, Bonita Montero wrote:
Am 01.06.2025 um 09:43 schrieb Lawrence D'Oliveiro:
On Sun, 1 Jun 2025 07:58:54 +0200, Bonita Montero wrote:
Sth. like this:
for( directory_entry const &de : recursive_directory_iterator( "\\", >>>>> directory_options::follow_directory_symlink ) )
cout << de.path() << endl;
You need the dirfd functions to avoid certain potential security
holes on operations with symlinks.
Which security holes ?
TOCTOU.
That's unavoidable with directory-operations.
That's unavoidable with directory-operations.
Incorrect. The entire purpose of the POSIX *at functions are to close
those security holes.
Muttley@DastardlyHQ.org writes:
Ugh. Then you end up like the Java JVM - grabbing boatloads of memory that >>causes huge startup delays and can often cause the machine to do lots of >>swapping and/or slow everything else down to treacle.
That's a problem with host not being suitable for java, if that
is the behavior you are seeing. I've not seen that in production
java-based applications that are competently developed.
For C/C++, one generally allocates page-aligned regions with mmap, eschewing >granular allocation methods such as new/delete/malloc.
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
Richard Harnden <richard.harnden@gmail.invalid> writes:
On 22/05/2025 23:32, Keith Thompson wrote:
[...]
In one of your library's headers:
extern const char ESCAPE;
In the corresponding *.c file:
const char ESCAPE = ('z' - 'a' == 25 ? '\x1b' : '\x27');
Change the name if you prefer.
Wouldn't that be a reserved identifier?
Yes, it would. Good catch.
(Identifiers starting with E followed by either a digit or an
uppercase letter are reserved; they could be defined as macros
in <errno.h>.)
They are reserved only as macros, and only if <errno.h> has
been #include'd.
For this particular use, it's easy to make the definition work,
simply by adding
#undef ESCAPE
before the declaration in the header file, and before the
definition in the source file (assuming of course that if
there are any #include <errno.h> they precede the #undef's).
It would be even easier to pick a different name.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 03.06.2025 um 02:37 schrieb Lawrence D'Oliveiro:
On Mon, 2 Jun 2025 09:35:24 +0200, Bonita Montero wrote:
Am 01.06.2025 um 09:43 schrieb Lawrence D'Oliveiro:
On Sun, 1 Jun 2025 07:58:54 +0200, Bonita Montero wrote:
Sth. like this:
for( directory_entry const &de : recursive_directory_iterator( "\\", >>>>>> directory_options::follow_directory_symlink ) )
cout << de.path() << endl;
You need the dirfd functions to avoid certain potential security
holes on operations with symlinks.
Which security holes ?
TOCTOU.
That's unavoidable with directory-operations.
Incorrect. The entire purpose of the POSIX *at functions are to close
those security holes.
Muttley@DastardlyHQ.org writes:
On Mon, 09 Jun 2025 18:33:38 GMT
scott@slp53.sl.home (Scott Lurndal) wibbled:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 09.06.2025 um 17:53 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 09.06.2025 um 16:01 schrieb Scott Lurndal:That's your problem caused by poor design and implementation.
Have you ever written real-world production code? Like an operating >>>>>>> system, where allocation failures should -never- result in an
inability to recover.
If you need an allocation to proceed and it fails you can't recover. >>>>>
That's how 100% of all programs that deal with bad_alloc are designed. >>>>
Exacerbated by the propensity for you to use C++ features that require >>>>> dynamic allocation where other forms of data structures are more suitable.
When dynamic allocation is needed it is needed.
And there are many ways to handle it that don't include throwing
bad_alloc when the system is unable to provide additional address
space, memory or backing store.
Allocating major data structures at application start (perhaps using a
pool allocator) and crafting your algorithms such that they
don't require infinite memory is a good start.
Ugh. Then you end up like the Java JVM - grabbing boatloads of memory that >> causes huge startup delays and can often cause the machine to do lots of
swapping and/or slow everything else down to treacle.
That's a problem with host not being suitable for java, if that
is the behavior you are seeing. I've not seen that in production
java-based applications that are competently developed.
For C/C++, one generally allocates page-aligned regions with mmap, eschewing granular allocation methods such as new/delete/malloc.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 09.06.2025 um 17:53 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 09.06.2025 um 16:01 schrieb Scott Lurndal:
Have you ever written real-world production code? Like an operating >>>>> system, where allocation failures should -never- result in an
inability to recover.
If you need an allocation to proceed and it fails you can't recover.
That's your problem caused by poor design and implementation.
That's how 100% of all programs that deal with bad_alloc are designed.
Exacerbated by the propensity for you to use C++ features that requireWhen dynamic allocation is needed it is needed.
dynamic allocation where other forms of data structures are more suitable. >>
And there are many ways to handle it that don't include throwing
bad_alloc when the system is unable to provide additional address
space, memory or backing store.
Allocating major data structures at application start (perhaps using a
pool allocator) and crafting your algorithms such that they
don't require infinite memory is a good start.
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:[...]
Richard Harnden <richard.harnden@gmail.invalid> writes:
On 22/05/2025 23:32, Keith Thompson wrote:
In one of your library's headers:
extern const char ESCAPE;
In the corresponding *.c file:
const char ESCAPE = ('z' - 'a' == 25 ? '\x1b' : '\x27');
Change the name if you prefer.
Wouldn't that be a reserved identifier?
Yes, it would. Good catch.
(Identifiers starting with E followed by either a digit or an
uppercase letter are reserved; they could be defined as macros
in <errno.h>.)
They are reserved only as macros, and only if <errno.h> has
been #include'd.
For this particular use, it's easy to make the definition work,
simply by adding
#undef ESCAPE
before the declaration in the header file, and before the
definition in the source file (assuming of course that if
there are any #include <errno.h> they precede the #undef's).
It would be even easier to pick a different name.
The point of my comment was to help explain the rules about what
macro names are reserved and under what circumstances, not to
suggest a way to avoid conflicts.
A better way to avoid conflicts with E* macros is to take functions
where errno is needed, as for example signal(), and not call them
directly but rather wrap each one in a function, with the wrapping
functions put in (one or more) separate translation unit(s). Those translation units, and only those translation units, are the ones
where a #include <errno.h> is done. Some details are needed to keep
the separation complete, but I think those aren't too hard to work
out, so if someone has trouble please ask. This way most of the
program can use names beginning with E that might otherwise be
reserved, without any fear of conflicts. There is a bit of source
code overhead, but that is paid only once, across all projects that
use this approach. Also there are some other benefits, related to
libraries used that are not part of ISO C, such as Posix, which
again should be readily apparent to anyone used to working in large
projects that use such libraries.
I find the reservation of potential errno macro names annoying.
On 2025-06-10, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
I find the reservation of potential errno macro names annoying.
If the standard contained /no/ statements about what a given header
file may reserve, then /any/ identifier whatsoever would be a potential clash.
The errno reservation is kind of good because implementors often extend
the set of errno constants. POSIX has a lot more of them than ISO C, and there are some vendor-specific ones.
Anyway, you can safely ignore the reservation theatre, and just
deal with clashes that happen, when they happen. (If you're lucky,
that could just be never).
Anyway, ISO C, POSIX and vendors have historically introduced new
identifiers in spaces that were not previously declared as reserved.
If you're ever hit by that, you will feel like a completel sucker if
you've religiously adhered to namespaces from your end.
Am 03.06.2025 um 02:37 schrieb Lawrence D'Oliveiro:\",
On Mon, 2 Jun 2025 09:35:24 +0200, Bonita Montero wrote:
Am 01.06.2025 um 09:43 schrieb Lawrence D'Oliveiro:
On Sun, 1 Jun 2025 07:58:54 +0200, Bonita Montero wrote:
Sth. like this:
for( directory_entry const &de : recursive_directory_iterator( "\
directory_options::follow_directory_symlink ) )
cout << de.path() << endl;
You need the dirfd functions to avoid certain potential security
holes on operations with symlinks.
Which security holes ?
TOCTOU.
That's unavoidable with directory-operations.
Kaz Kylheku <643-408-1753@kylheku.com> writes:
On 2025-06-10, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
I find the reservation of potential errno macro names annoying.
If the standard contained /no/ statements about what a given header
file may reserve, then /any/ identifier whatsoever would be a potential
clash.
The errno reservation is kind of good because implementors often extend
the set of errno constants. POSIX has a lot more of them than ISO C, and
there are some vendor-specific ones.
Anyway, you can safely ignore the reservation theatre, and just
deal with clashes that happen, when they happen. (If you're lucky,
that could just be never).
You can do that, but a new clash could happen when your code is
compiled on a system that defines an errno macro that you haven't
seen before.
Anyway, ISO C, POSIX and vendors have historically introduced new
identifiers in spaces that were not previously declared as reserved.
If you're ever hit by that, you will feel like a completel sucker if
you've religiously adhered to namespaces from your end.
Yes, that can happen, but no, I won't feel like a complete sucker.
If I define my own strfoo() function and a new edition of the standard defines strfoo() in <string.h>, the clash is my fault,and I could have avoided it by defining str_foo().
On 2025-06-10, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
Kaz Kylheku <643-408-1753@kylheku.com> writes:
On 2025-06-10, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
I find the reservation of potential errno macro names annoying.
If the standard contained /no/ statements about what a given header
file may reserve, then /any/ identifier whatsoever would be a potential
clash.
The errno reservation is kind of good because implementors often extend
the set of errno constants. POSIX has a lot more of them than ISO C, and >>> there are some vendor-specific ones.
Anyway, you can safely ignore the reservation theatre, and just
deal with clashes that happen, when they happen. (If you're lucky,
that could just be never).
You can do that, but a new clash could happen when your code is
compiled on a system that defines an errno macro that you haven't
seen before.
A new CRASH could happen too, and any number of things.
This clash would be literally one of the first roadblocks, if not the
first one, that we would see when just exploring the possibility whether
our code might not run on that system.
At that point we could be months away from declaring that a supported platform.
Anyway, ISO C, POSIX and vendors have historically introduced new
identifiers in spaces that were not previously declared as reserved.
If you're ever hit by that, you will feel like a completel sucker if
you've religiously adhered to namespaces from your end.
Yes, that can happen, but no, I won't feel like a complete sucker.
If I define my own strfoo() function and a new edition of the standard
defines strfoo() in <string.h>, the clash is my fault,and I could have
avoided it by defining str_foo().
But, my point is, that maybe you could have called it kidneybeans() and
still have a clash.
In fact, if you are writing new string functions that are the same sort
of stuff like the standard ones, you should use the str prefix,
for consistency.
If your code is influential enough, they might be standardized one
day---and then they are ready with the proper naming, so early adopters
of your functions won't have to change anything; just in their build
system drop the third party code and switch to what their library now provides.
No it isn’t. That’s why we have the fd-based calls in recent POSIX, and in
Linux. That plugs the holes, and makes it possible to implement privileged file-access software like Samba securely.
Am 11.06.2025 um 01:33 schrieb Lawrence D'Oliveiro:
No it isn’t. That’s why we have the fd-based calls in recent POSIX, and >> in Linux. That plugs the holes, and makes it possible to implement
privileged file-access software like Samba securely.
opendir() and readdir() hasn't changed for decades.
Am 11.06.2025 um 01:33 schrieb Lawrence D'Oliveiro:
No it isn’t. That’s why we have the fd-based calls in recent POSIX, and in
Linux. That plugs the holes, and makes it possible to implement privileged >> file-access software like Samba securely.
opendir() and readdir() hasn't changed for decades.
Kaz Kylheku <643-408-1753@kylheku.com> writes:
On 2025-06-10, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
Kaz Kylheku <643-408-1753@kylheku.com> writes:
On 2025-06-10, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
I find the reservation of potential errno macro names annoying.
If the standard contained /no/ statements about what a given header
file may reserve, then /any/ identifier whatsoever would be a potential >>>> clash.
The errno reservation is kind of good because implementors often extend >>>> the set of errno constants. POSIX has a lot more of them than ISO C, and >>>> there are some vendor-specific ones.
Anyway, you can safely ignore the reservation theatre, and just
deal with clashes that happen, when they happen. (If you're lucky,
that could just be never).
You can do that, but a new clash could happen when your code is
compiled on a system that defines an errno macro that you haven't
seen before.
A new CRASH could happen too, and any number of things.
Sure, but a compilation failure is more likely.
This clash would be literally one of the first roadblocks, if not the
first one, that we would see when just exploring the possibility whether
our code might not run on that system.
At that point we could be months away from declaring that a supported
platform.
Sure, but why not skip that first roadblock?
Anyway, ISO C, POSIX and vendors have historically introduced new
identifiers in spaces that were not previously declared as reserved.
If you're ever hit by that, you will feel like a completel sucker if
you've religiously adhered to namespaces from your end.
Yes, that can happen, but no, I won't feel like a complete sucker.
If I define my own strfoo() function and a new edition of the standard
defines strfoo() in <string.h>, the clash is my fault,and I could have
avoided it by defining str_foo().
But, my point is, that maybe you could have called it kidneybeans() and
still have a clash.
Certainly, I've already acknowledged that.
But surely an identifier that the standard says is reserved is less
likely to cause a clash than one that isn't.
In fact, if you are writing new string functions that are the same sort
of stuff like the standard ones, you should use the str prefix,
for consistency.
If your code is influential enough, they might be standardized one
day---and then they are ready with the proper naming, so early adopters
of your functions won't have to change anything; just in their build
system drop the third party code and switch to what their library now
provides.
I see your point, but ... meh. To me, a name matching "str[a-z]*"
fairly strongly suggests a function declared in <string.h> in ISO C.
Of course it's not an absolute rule; see strlcpy(), for example
(which is now part of POSIX).
Even a str*() identifier that never clashes with ISO C's <string.h>
can still clash with POSIX, or glibc, or BSD, or ....
I would have been happier if POSIX were less intrusive on the
C standard library, but the way C and POSIX evolved didn't make
that feasible.
I find the reservation of potential errno macro names annoying.
That turns out to not be true. fdopendir(3) was added in Issue
7 of the Single Unix Specification (aka POSIX). https://pubs.opengroup.org/onlinepubs/9799919799/functions/fdopendir.html ftw(3)/nftw(3) are used more often than opendir(3) in real world code.
Kaz Kylheku <643-408-1753@kylheku.com> writes:
On 2025-06-10, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
I find the reservation of potential errno macro names annoying.
If the standard contained /no/ statements about what a given header
file may reserve, then /any/ identifier whatsoever would be a potential
clash.
The errno reservation is kind of good because implementors often extend
the set of errno constants. POSIX has a lot more of them than ISO C, and
there are some vendor-specific ones.
Anyway, you can safely ignore the reservation theatre, and just
deal with clashes that happen, when they happen. (If you're lucky,
that could just be never).
You can do that, but a new clash could happen when your code is
compiled on a system that defines an errno macro that you haven't
seen before.
Anyway, ISO C, POSIX and vendors have historically introduced new
identifiers in spaces that were not previously declared as reserved.
If you're ever hit by that, you will feel like a completel sucker if
you've religiously adhered to namespaces from your end.
Yes, that can happen, but no, I won't feel like a complete sucker.
If I define my own strfoo() function and a new edition of the standard defines strfoo() in <string.h>, the clash is my fault,and I could have avoided it by defining str_foo().
Nothing can prevent all possible name clashes, but I like to follow the
rules in the standard that let me prevent some of them.
[fdopendir] doesn't make a difference for the discussed point.
On 28/05/2025 13:41, Tim Rentsch wrote:
Richard Heathfield <rjh@cpax.org.uk> writes:
On 24/05/2025 06:32, Tim Rentsch wrote:
Richard Heathfield <rjh@cpax.org.uk> writes:
On 23/05/2025 13:43, Tim Rentsch wrote:
Richard Heathfield <rjh@cpax.org.uk> writes:
On 20/05/2025 10:18, Keith Thompson wrote:
C90 will never be extended.
And for that reason it will always be valuable. Stability
has a value all its own.
C99 is just as stable as C90, and has been for well over a
decade.
Sure, but it's a different stable.
If it were the same stable, it would be C90.
C99 isn't C90, therefore it isn't the same stable.
If you tell me C99 is a rock, I will not doubt you. But the C90
rock it most certainly isn't.
Now you're being silly.
No, sir. If you want to play that game, you can play it with
yourself. I know that you are perfectly capable of polite
conversation, so I see no reason to endure the opposite.
I don't think I'm being impolite.
Then we are again in disagreement, and it seems obvious that it would
be foolishly optimistic of me to expect to be able to resolve the
matter. I'll tell Thunderbird to leave it there.
On 30/05/2025 10:20, David Brown wrote:
On 29/05/2025 14:38, Richard Heathfield wrote:
This really is a very simple point, but perhaps a simple analogy
will help to clarify it. You don't throw out your 3/4" just
because you've bought a 19mm. There is room for both in the
toolbox, and why write 3/4" on your new spanner? It /isn't/ a
3/4" spanner even though it's very like it, so why pretend
otherwise?
Your analogy does not cover C99 vs C90.
It does if we can construct a program that is legal C90 but not
legal C99, which is easy enough, or (slightly harder but still not
that hard) a program that is legal in both dialects but which
gives different output under C99 than it does for C90.
$ cat c9099.c; \
gcc -W -Wall -ansi -pedantic -o c90 c9099.c; \
gcc -o c99 c9099.c; \
./c90; \
./c99
#include <stdio.h>
int main(void)
{
int a = 42;
int b = a //* comment */ 6;
;
printf("Soln = %d\n", b);
return 0;
}
Soln = 7
Soln = 42
Obviously it's a contrived example, but then examples pointing out
the consequences of language differences invariably are.
"Lawrence D'Oliveiro" <ldo@nz.invalid> wrote in message news:100jhor$2lgt3$4@dont-email.me...
On Wed, 21 May 2025 10:23:27 +1000, Paul Edwards wrote:...
The C90 standard deferred to MVS - probably still does -
and says that you can't open a file as "w", then read it as
"rb" and write (a new file) as "wb", and still access (the
new file) with "r".
I was shocked when I saw IBM's C library lose the newlines
when I did the above, and went to look at the standard to
show that IBM was violating C90 - but it turns out they
weren't.
That sort of means you can't write a "zip" program portably,
against the theoretical C90 file system. Or you would have
to have flags to say which files need to be opened as text
or binary.
I do not agree with IBM's C library, and PDPCLIB does
not have that behavior, so that constraint could potentially
be dropped in a C90+ standard.
BFN. Paul.
Lawrence D'Oliveiro <ldo@nz.invalid> writes:
On Thu, 22 May 2025 02:20:36 +0200, Jakob Bohm wrote:
The later UNIX-like file system NTFS ...
It was (and is) hard to describe NTFS as “Unix-like”. Yes, it had
hierarchical directories and long(ish) file names, but not much else.
Drive letters were inherited (indirectly) from DEC OSes, of all things,
along with an insistence on having filename extensions, restrictions on
characters allowed in names etc.
I don't believe that NTFS requires filename extensions.
My understanding is that a file name is stored as a single string
(with some restrictions).
Symlinks were not even added until Windows Vista. And you have to have
special privileges to create them.
Do note one more thing.
The C90 standard deferred to MVS - probably still does -
and says that you can't open a file as "w", then read it as
"rb" and write (a new file) as "wb", and still access (the
new file) with "r".
I was shocked when I saw IBM's C library lose the newlines
when I did the above, and went to look at the standard to
show that IBM was violating C90 - but it turns out they
weren't.
That sort of means you can't write a "zip" program portably,
against the theoretical C90 file system.
Or you would have
to have flags to say which files need to be opened as text
or binary.
On 2025-05-21, Paul Edwards <mutazilah@gmail.com> wrote:...
Do note one more thing.
The C90 standard deferred to MVS - probably still does -
and says that you can't open a file as "w", then read it as
"rb" and write (a new file) as "wb", and still access (the
new file) with "r".
You mean:
- write a text file, close it; then
- open it as a binary file and copy the bytes to another, new binary file; and
- finally, read the new binary file in text mode?
I don't see how that would be allowed to lose any newlines.
You made a bitwise copy of the file.
A recent draft of ISO C says "A binary stream is an ordered sequence of characters that can transparently record internal data. Data read in
from a binary stream shall compare equal to the data that were earlier written out to that stream, under the same implementation. Such a stream
may, however, have an implementation- defined number of null characters appended to the end of the stream."
I have C90 somewhere, I can look that up too, but I suspect it was
the same.
I was shocked when I saw IBM's C library lose the newlines
when I did the above, and went to look at the standard to
show that IBM was violating C90 - but it turns out they
weren't.
Sysop: | DaiTengu |
---|---|
Location: | Appleton, WI |
Users: | 1,065 |
Nodes: | 10 (0 / 10) |
Uptime: | 106:39:47 |
Calls: | 13,703 |
Files: | 186,945 |
D/L today: |
907 files (307M bytes) |
Messages: | 2,413,700 |