getdelim: wrong specs

K

Keith Thompson

Richard Heathfield said:
Richard Bos said:

However, [errno] has one great advantage: it is Standard ISO C,

That doesn't mean it is universally supported, however. I know of at least
one otherwise-conforming implementation which doesn't support errno
correctly. Yet another reason for avoiding it completely.

Which implementation is it, and how does it fail?
 
R

Richard Heathfield

Keith Thompson said:
Richard Heathfield said:
Richard Bos said:

However, [errno] has one great advantage: it is Standard ISO C,

That doesn't mean it is universally supported, however. I know of at
least one otherwise-conforming implementation which doesn't support errno
correctly. Yet another reason for avoiding it completely.

Which implementation is it, and how does it fail?

Borland. My failures to get errno to work were, AFAICR, on 3.1, 4.5, 5.02,
and one later version, which I could check if I had to. Don't ask me how
because it's been years, but if you can get a strictly-conforming
errno-using program to compile using *any* version of Borland, I'll eat
humble pie, and gladly, provided you tell me how you did it!

As far as I can recall, if you #include <errno.h>, that's fine - but if you
try to use errno, Borland says it's undefined. If you then make the mistake
of trying to define it, Borland says it's multiply defined.

So either Borland's errno is broken, or I'm missing something major. Time
was when I'd have blamed me. I'm still willing to do that, but I'd like to
see some evidence that Borland is in fact blameless and that I've just been
running from my own errno ignorance for several years.
 
R

Richard Bos

pete said:
Richard said:
Richard Bos said:

However, [errno] has one great advantage: it is Standard ISO C,

That doesn't mean it is universally supported, however.
I know of at least
one otherwise-conforming implementation which doesn't support errno
correctly. Yet another reason for avoiding it completely.

I've never like the concept of EDOM.

That a programmer would write code to initialise errno
and check it after a function call, rather than to ensure
that the arguments were in the domain of the function,
seems strange to me.

For one single, intimately know implementation, you're right. But if you
want to compile your code on several platforms, or on several
generations of one implementation (e.g., a 16-bit and a much later
32-bit one), it's not always viable to know where the limits of, say,
pow() lie without doing the computation to begin with.

Richard
 
S

santosh

Richard said:
Keith Thompson said:
Richard Heathfield said:
Richard Bos said:

<snip>

However, [errno] has one great advantage: it is Standard ISO C,

That doesn't mean it is universally supported, however. I know of at
least one otherwise-conforming implementation which doesn't support errno
correctly. Yet another reason for avoiding it completely.

Which implementation is it, and how does it fail?

Borland. My failures to get errno to work were, AFAICR, on 3.1, 4.5, 5.02,
and one later version, which I could check if I had to. Don't ask me how
because it's been years, but if you can get a strictly-conforming
errno-using program to compile using *any* version of Borland, I'll eat
humble pie, and gladly, provided you tell me how you did it!
<snip>

I would've thought that failure to implement errno properly would be
_major_ defect, that would've raised hell from thousands of programmers
and fixed in the very next release. It's surprising that three major
versions of the compiler have such a bug.

Or is it that errno like register, enum, volatile and ?:, a rarely used
feature of C programming, so Borland's fault with regard to it was
simply not noticeable enough to spur them to fix it?

Some years back I used Borland 5.5, but I don't recall ever exploiting
errno.h. Now I'm on Linux and Windows has been nuked.
 
R

Richard Heathfield

santosh said:

I would've thought that failure to implement errno properly would be
_major_ defect, that would've raised hell from thousands of programmers
and fixed in the very next release. It's surprising that three major
versions of the compiler have such a bug.

Yes, I would've thought that too, which is why I remain open to the
possibility that I've simply done something really stupid, and so my
dissing of Borland is unfair. So - can anyone else get errno to work
properly in a strictly-conforming program under a C compiler from Borland?
If so, could they please post the program, and say under which Borland
version(s) it works correctly?
 
G

Guest

Richard said:
santosh said:



Yes, I would've thought that too, which is why I remain open to the
possibility that I've simply done something really stupid, and so my
dissing of Borland is unfair. So - can anyone else get errno to work
properly in a strictly-conforming program under a C compiler from Borland?
If so, could they please post the program, and say under which Borland
version(s) it works correctly?

I would be surprised if there is a legitimate use of errno in a
strictly conforming program, but if you don't mind unspecified output,
this works in Borland C++ 5.5 (in C mode):

#include <stdio.h>
#include <errno.h>

int main(void) {
FILE *fp;
errno = 0;
fp = fopen("", "r");
if(fp != NULL)
fclose(fp); /* ??? */
else if(errno == 0)
fputs("errno was not set\n", stderr);
else
fputs(strerror(errno), stderr);
return 0;
}

It outputs "No such file or directory" followed by a newline.
 
G

Guest

Harald said:
I would be surprised if there is a legitimate use of errno in a
strictly conforming program, but if you don't mind unspecified output,
this works in Borland C++ 5.5 (in C mode):

#include <stdio.h>

#include said:
#include <errno.h>

int main(void) {
FILE *fp;
errno = 0;
fp = fopen("", "r");
if(fp != NULL)
fclose(fp); /* ??? */
else if(errno == 0)
fputs("errno was not set\n", stderr);
else
fputs(strerror(errno), stderr);
return 0;
}

It outputs "No such file or directory" followed by a newline.

Sorry about that.
 
J

Jun Woong

Richard said:
For one single, intimately know implementation, you're right. But if you
want to compile your code on several platforms, or on several
generations of one implementation (e.g., a 16-bit and a much later
32-bit one), it's not always viable to know where the limits of, say,
pow() lie without doing the computation to begin with.

Aren't you being confused with ERANGE here?

pete has a point. At least to me, it seems more natural for a
programmer to check if the argument is in the standard-defined
domain of a math function before passing it to the function. But,
considering that the domain error is an open-ended set for a function
(e.g., passing Inf to a function results in the domain error?), EDOM
is still necessary, I think.


--
Jun, Woong (woong at icu.ac.kr)
Samsung Electronics Co., Ltd.

``All opinions expressed are mine, and do not represent
the official opinions of any organization.''
 
R

Richard Heathfield

Harald van D?k said:
I would be surprised if there is a legitimate use of errno in a
strictly conforming program,

Oh, I hadn't thought of that. :)

What I actually meant was a clc-conforming program, if you see what I mean.
but if you don't mind unspecified output,
this works in Borland C++ 5.5 (in C mode):

No time right now - I'll check it as soon as I get home. (After getting my
coat off, making some coffee, ... but you get the idea.)
 
S

SuperKoko

Richard said:
Borland. My failures to get errno to work were, AFAICR, on 3.1, 4.5, 5.02,
and one later version, which I could check if I had to. Don't ask me how
because it's been years, but if you can get a strictly-conforming
errno-using program to compile using *any* version of Borland, I'll eat
humble pie, and gladly, provided you tell me how you did it!

The following non-strictly conforming (unspecified behavior) program
works well with Borland C 5.0 (Win32, DOS tiny, small, medium, compact,
large and huge memory models), Borland C 5.5.1 and Turbo C 2.01.

#include <stdio.h>
#include <errno.h>

int main() {
FILE* f;
errno=0;
f=fopen("hello.txt", "r");
if (!f) {
printf("%d\n", (int)errno);
}
return 0;
}

The file "hello.txt" doesn't exist in the current directory, and the
program outputs 2.

And here is a strictly conforming program "using errno".

#include <errno.h>

int main() {
errno=0;
return 0;
}

It works as well with Borland C 5.5.1, Borland C 5.0 (Win32 and all DOS
memory models), and Turbo C 2.01.
As far as I can recall, if you #include <errno.h>, that's fine - but if you
try to use errno, Borland says it's undefined. If you then make the mistake
of trying to define it, Borland says it's multiply defined.
I have not this problem.
Maybe your installation is broken.
 
D

Douglas A. Gwyn

pete said:
I've never like the concept of EDOM.
That a programmer would write code to initialise errno
and check it after a function call, rather than to ensure
that the arguments were in the domain of the function,
seems strange to me.

Originally, EDOM was intended for math functions, where
an exact test for "within the domain" might be difficult
(consider atan), and also to catch accidents (programming
explicit validity tests before every usage is so tedious,
especially when one expects all usage to be valid, that
you can't rely on users to do it). It would have been
much better to have used a generic nested-exception
handling facility, which allows fine-grained override of
global error-handling strategy. A sort of in-between
approach showed up in the commercial branch of Unix, in
the form of a function named "matherror" for which the
user could substitute his own version.
 
R

Richard Heathfield

Richard Heathfield said:
Harald van D?k said:


No time right now - I'll check it as soon as I get home. (After getting my
coat off, making some coffee, ... but you get the idea.)

<sigh> Better late than never. Anyway, I've just checked your code in BC5.6
and it works fine. So either they finally fixed this, or I was imagining
things. Which do you reckon? (Don't answer that...)
 
J

Jun Woong

Douglas said:
Originally, EDOM was intended for math functions, where
an exact test for "within the domain" might be difficult
(consider atan),
Reasonable.

and also to catch accidents (programming
explicit validity tests before every usage is so tedious,
especially when one expects all usage to be valid, that
you can't rely on users to do it).

I doubt that justifies existence of EDOM; that's what we're doing in
C everyday.


--
Jun, Woong (woong at icu.ac.kr)
Samsung Electronics Co., Ltd.

``All opinions expressed are mine, and do not represent
the official opinions of any organization.''
 
R

Richard Bos

CBFalconer said:
Take a look at the error reporting in ggets. It is controlled by
an enum for positive values, and EOF for negative values. No
possibility of overflow (which in itself would be undefined
behaviour) exist.

That's arguably better design, but it's not the design that was used in
the proposed getdelim() specification in the first place. Using EOF as
an in-band error value for that was less than ideal; using -1 through
-5, disregarding possible other values of EOF than -1, is worse.

Richard
 
J

jacob navia

Richard Bos a écrit :
That's arguably better design, but it's not the design that was used in
the proposed getdelim() specification in the first place. Using EOF as
an in-band error value for that was less than ideal; using -1 through
-5, disregarding possible other values of EOF than -1, is worse.

Richard

No it is not. The result value is a ssize_t, i.e. a signed size_t.
This means that all negative values are free to use as error
values since the valid return values are from zero to INT_MAX.

ssize_t getdelim(char **restrict lineptr,
size_t *restrict n,
int delimiter, FILE *stream);
 
C

CBFalconer

jacob said:
Richard Bos a écrit :

No it is not. The result value is a ssize_t, i.e. a signed size_t.
This means that all negative values are free to use as error
values since the valid return values are from zero to INT_MAX.

ssize_t getdelim(char **restrict lineptr,
size_t *restrict n,
int delimiter, FILE *stream);

There is no guarantee as to the value of EOF, other than that it is
negative. Any mapping into a size_t runs the risk of clashes. Use
an int to return EOF.
 
K

Keith Thompson

CBFalconer said:
There is no guarantee as to the value of EOF, other than that it is
negative. Any mapping into a size_t runs the risk of clashes. Use
an int to return EOF.

You could declare an enumerated type whose constants specify the
various error conditions. The values of the constants wouldn't have
to be consistent from one implementation to another, just their names.
It would be up to the implementer to avoid colliding with the value of
EOF. (EOF is -1 on every implementation I've ever heard of; a
programmer can't safely make that assumption, but an implementer can.)

For example:

enum {
ERROR_MAX = -2,
ERROR_FOO = -2,
ERROR_BAR = -3,
ERROR_BAZ = -4,
ERROR_XYZ = -5,
ERROR_MIN = -5
};

There's no tag for the enumerated type because it's used only to
declare a series of constants.

getdelim() could still return ssize_t (I've lost track, are we
assuming that ssize_t exists?), and it could be used like this:

ssize_t result = getdelim(arg1, arg2, arg3, arg4);
if (result >= 0) {
/* ... */
}
else if (result == EOF) {
/* ... */
}
else if (result >= ERROR_MIN && result <= ERROR_MAX) {
switch(result) {
case ERROR_FOO: /* ... */
/* ... */
default: /* ... */
}
}

This lets you squeeze valid results, EOF, and multiple error codes
into a single return value. It also assumes that losing half the
range of size_t isn't a problem.

I'm not claiming that this is a particularly good approach, just that
it's possible.
 
B

Ben Pfaff

Keith Thompson said:
You could declare an enumerated type whose constants specify the
various error conditions. The values of the constants wouldn't have
to be consistent from one implementation to another, just their names.
It would be up to the implementer to avoid colliding with the value of
EOF. (EOF is -1 on every implementation I've ever heard of; a
programmer can't safely make that assumption, but an implementer can.)

I think that this kind of dodge would consistently avoid EOF and
positive values:

enum {
MY_ERR_MIN = EOF ^ 0x100,

MY_ERR_FIRSTERR = MY_ERR_MIN,
MY_ERR_SECONDERR,
MY_ERR_ANOTHERERR,
...etc...

MY_ERR_SENTINEL,
MY_ERR_MAX = MY_ERR_SENTINEL - 1
};
 
J

jacob navia

Keith said:
You could declare an enumerated type whose constants specify the
various error conditions. The values of the constants wouldn't have
to be consistent from one implementation to another, just their names.
It would be up to the implementer to avoid colliding with the value of
EOF. (EOF is -1 on every implementation I've ever heard of; a
programmer can't safely make that assumption, but an implementer can.)

For example:

enum {
ERROR_MAX = -2,
ERROR_FOO = -2,
ERROR_BAR = -3,
ERROR_BAZ = -4,
ERROR_XYZ = -5,
ERROR_MIN = -5
};

There's no tag for the enumerated type because it's used only to
declare a series of constants.

getdelim() could still return ssize_t (I've lost track, are we
assuming that ssize_t exists?), and it could be used like this:

ssize_t result = getdelim(arg1, arg2, arg3, arg4);
if (result >= 0) {
/* ... */
}
else if (result == EOF) {
/* ... */
}
else if (result >= ERROR_MIN && result <= ERROR_MAX) {
switch(result) {
case ERROR_FOO: /* ... */
/* ... */
default: /* ... */
}
}

This lets you squeeze valid results, EOF, and multiple error codes
into a single return value. It also assumes that losing half the
range of size_t isn't a problem.

I'm not claiming that this is a particularly good approach, just that
it's possible.


This looks VERY reasonable. Thanks

jacob
 
K

Keith Thompson

jacob navia said:
Keith Thompson wrote: [...]
It would be up to the implementer to avoid colliding with the value of
EOF. (EOF is -1 on every implementation I've ever heard of; a
programmer can't safely make that assumption, but an implementer can.)
For example:
[big snip]
This looks VERY reasonable. Thanks

jacob

Um, I have mixed feelings about that. I was trying to create the most
reasonable design given the assumption that you want to squeeze valid
results, EOF, and multiple error conditions into a single return
value. Personally, I don't particularly like the assumption.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,276
Latest member
Sawatmakal

Latest Threads

Top