By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,570 Members | 1,245 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,570 IT Pros & Developers. It's quick & easy.

getdelim: wrong specs

P: n/a
In the documents presented in the post Portland meeting
of the C standards comitee
http://www.open-std.org/jtc1/sc22/wg14/

there is a document called ISO/IEC WDTR 24731-2,
Specification for Safer C Library Functions —
Part II: Dynamic Allocation Functions

In that document we have:
ssize_t getdelim(char **restrict lineptr,
size_t *restrict n, int delimiter, FILE *stream);

We read:
< quote >

Upon successful completion the getdelim function shall return the number
of characters written into the buffer, including the delimiter character
if one was encountered before EOF. Otherwise it shall return −1.

< end quote >

We come back here to the error analysis problem, a problem that I
have been mentioning since ages and comes again and again. Returning
-1 to indicate "some error occurred but I will not tell you which"
is BAD DESIGN!

This function can have several errors that should be distinguished in
the return value of the function, i.e. there should be other return
values for signaling errors to the user. Lcc-win32 implements this
function and returns:

-5 No memory left for allocating the line
-4 Line pointer points to a buffer but n is <= 0. This is an error in
the incoming arguments.
-3 The n parameter is NULL
-2 The LinePointer parameter is NULL
-1 End of file without any characters read.

This is a much more detailed error reporting, that allows the
user of the function to discriminate between the different error
conditions. It is sad that a document that proposed "safer" functions
doesn't do the error analysis that is an essential part of safer
programming.
Dec 3 '06 #1
Share this Question
Share on Google+
61 Replies


P: n/a
jacob navia wrote:
>
In the documents presented in the post Portland meeting
of the C standards comitee
http://www.open-std.org/jtc1/sc22/wg14/

there is a document called ISO/IEC WDTR 24731-2,
Specification for Safer C Library Functions —
Part II: Dynamic Allocation Functions

In that document we have:
ssize_t getdelim(char **restrict lineptr,
size_t *restrict n, int delimiter, FILE *stream);

We read:
< quote >

Upon successful completion the getdelim function shall return the number
of characters written into the buffer, including the delimiter character
if one was encountered before EOF. Otherwise it shall return −1.

< end quote >

We come back here to the error analysis problem, a problem that I
have been mentioning since ages and comes again and again. Returning
-1 to indicate "some error occurred but I will not tell you which"
is BAD DESIGN!

This function can have several errors that should be distinguished in
the return value of the function, i.e. there should be other return
values for signaling errors to the user. Lcc-win32 implements this
function and returns:

-5 No memory left for allocating the line
-4 Line pointer points to a buffer but n is <= 0. This is an error in
the incoming arguments.
Not if the buffer is allocated this way:
n = 0;
buffer = malloc(0);

ITYM "... but n equals 0"

-3 The n parameter is NULL
ITYM null, and that's not a problem.
-2 The LinePointer parameter is NULL
Not a problem either, if n equals 0.
-1 End of file without any characters read.

This is a much more detailed error reporting, that allows the
user of the function to discriminate between the different error
conditions. It is sad that a document that proposed "safer" functions
doesn't do the error analysis that is an essential part of safer
programming.
I've noticed that the next function listed, getline,
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
has exactly the same functionality as my line_to_string function,
(which I've posted enough times to be annoying recently
http://groups-beta.google.com/group/...694880f515e317)
but the return values are different.

line_to_string returns EOF upon an end of file condition
before reading a newline, or input error.
feof and ferror can be used to determine which.
"End of file without any characters read"
is a specific case of "before reading a newline".

line_to_string returns 0 if there is not enough memory.
if *size is less than 2 within the function,
then there is also a character pushback.

Otherwise, line_to_string returns
"the number of characters written into the buffer"
just like getline.

line_to_string always leaves a string in the buffer,
unless *size is zero within the function.

Both the pushback case and the no string in the buffer case,
can be definitely avoided,
by supplying a buffer with more than one byte,
in the call to line_to_string.

--
pete
Dec 3 '06 #2

P: n/a
pete a crit :
jacob navia wrote:
>>This function can have several errors that should be distinguished in
the return value of the function, i.e. there should be other return
values for signaling errors to the user. Lcc-win32 implements this
function and returns:

-5 No memory left for allocating the line
-4 Line pointer points to a buffer but n is <= 0. This is an error in
the incoming arguments.


Not if the buffer is allocated this way:
n = 0;
buffer = malloc(0);
This is ridiculous... Now what is the point of getting a line of zero
length???? This is surely an error!

ITYM "... but n equals 0"
>>-3 The n parameter is NULL


ITYM null, and that's not a problem.
The n parameter should never be NULL according to the specs...
>
>>-2 The LinePointer parameter is NULL


Not a problem either, if n equals 0.
No, because it can't return the result into *n!!! It will read
chars but it can't return them. This is nonsense...
Dec 3 '06 #3

P: n/a
jacob navia wrote:
>
pete a crit :
jacob navia wrote:
>This function can have several errors
that should be distinguished in
the return value of the function, i.e. there should be other return
values for signaling errors to the user. Lcc-win32 implements this
function and returns:

-5 No memory left for allocating the line
-4 Line pointer points to a buffer but n is <= 0.
This is an error in
the incoming arguments.

Not if the buffer is allocated this way:
n = 0;
buffer = malloc(0);

This is ridiculous... Now what is the point of getting a line of zero
length???? This is surely an error!

The point of getting a line of zero length,
is that that's not how the function works.

Recall the title of the document:
Part II: Dynamic Allocation Functions

A very simple way to call the function is:

ssize_t rc;
char *buffer = NULL;
size_t size = 0;

rc = getdelim(&buffer, &size, '\n', stdin);

In this post:
http://groups-beta.google.com/group/...a8ef6a9d40e578
line_to_string is called in just exactly that way.

/*
** INITIAL_BUFFER_SIZE can be any number.
** Lower numbers are more likely
** to get a non-NULL return value from malloc.
** Higher numbers are more likely to prevent
** any further allocation from being needed.
*/
#define INITIAL_BUFFER_SIZE 0

buff_size = INITIAL_BUFFER_SIZE;
buff_ptr = malloc(buff_size);
if (buff_ptr == NULL && buff_size != 0) {
printf("malloc(%lu) == NULL\n", (long unsigned)buff_size);
exit(EXIT_FAILURE);
}

rc = line_to_string(stdin, &buff_ptr, &buff_size)
ITYM "... but n equals 0"
>-3 The n parameter is NULL

ITYM null, and that's not a problem.

The n parameter should never be NULL according to the specs...
I misread that as *n being equal to NULL.
From your usage of "n is <= 0"
I assumed you meant n to be the buffer size
rather than the pointer to the size.
>-2 The LinePointer parameter is NULL

Not a problem either, if n equals 0.

No, because it can't return the result into *n!!! It will read
chars but it can't return them. This is nonsense...
Likewise, I meant if *n equals zero
and I also misread LinePointer to mean *LinePointer.

--
pete
Dec 3 '06 #4

P: n/a
jacob navia writes:
We come back here to the error analysis problem, a problem that I
have been mentioning since ages and comes again and again. Returning
-1 to indicate "some error occurred but I will not tell you which"
is BAD DESIGN!
Indeed. Why don't they just set errno though? It's not my favorite
way of reporting errors, but it _is_ the Standard C way. I don't
remember offhand any standard C functions which have several failure
return values instead.

--
Hallvard
Dec 3 '06 #5

P: n/a
jacob navia wrote:
>
In the documents presented in the post Portland meeting
of the C standards comitee
http://www.open-std.org/jtc1/sc22/wg14/

there is a document called ISO/IEC WDTR 24731-2,
Specification for Safer C Library Functions —
Part II: Dynamic Allocation Functions

In that document we have:
ssize_t getdelim(char **restrict lineptr,
size_t *restrict n, int delimiter, FILE *stream);

We read:
< quote >

Upon successful completion the getdelim function shall return the number
of characters written into the buffer, including the delimiter character
if one was encountered before EOF. Otherwise it shall return −1.

< end quote >

We come back here to the error analysis problem, a problem that I
have been mentioning since ages and comes again and again. Returning
-1 to indicate "some error occurred but I will not tell you which"
is BAD DESIGN!
But which you ignored in your proposed strndup function, and then
objected when I pointed it out. As I said then that document
originated with Microsoft, and is subject to the usual Microsoft
failings, i.e. it should be ignored.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Dec 3 '06 #6

P: n/a
Hallvard B Furuseth wrote:
jacob navia writes:
>>We come back here to the error analysis problem, a problem that I
have been mentioning since ages and comes again and again. Returning
-1 to indicate "some error occurred but I will not tell you which"
is BAD DESIGN!


Indeed. Why don't they just set errno though? It's not my favorite
way of reporting errors, but it _is_ the Standard C way. I don't
remember offhand any standard C functions which have several failure
return values instead.
strtol() returns either 0, LONG_MAX or LONG_MIN, which may or may not be
interpreted as error codes ;-)

Boa
Dec 3 '06 #7

P: n/a
On 2006-12-03 12:53, jacob navia wrote:
pete a crit :
>jacob navia wrote:
:
>Not if the buffer is allocated this way:
n = 0;
buffer = malloc(0);

This is ridiculous... Now what is the point of getting a line of zero
length???? This is surely an error!
Following your logic,

int n = 0;
...
int k = m + n;

is surely an error as well (better raise a signal or something),
and one should write

int k = m;
if (n != 0)
{
k += n;
}

instead...

-- Niklas Matthies
Dec 3 '06 #8

P: n/a
Niklas Matthies a crit :
On 2006-12-03 12:53, jacob navia wrote:
>>pete a crit :
>>>jacob navia wrote:

:
>>>Not if the buffer is allocated this way:
n = 0;
buffer = malloc(0);

This is ridiculous... Now what is the point of getting a line of zero
length???? This is surely an error!


Following your logic,

int n = 0;
...
int k = m + n;

is surely an error as well (better raise a signal or something),
and one should write

int k = m;
if (n != 0)
{
k += n;
}

instead...

-- Niklas Matthies
The straw man argument consists of making others believe that your
adversary has said something ridiculous, and absolutely absurd.

You take also a sentence where I say:

"What's the point of reading a line of zero length?"

to mean that I am against additions... How nice Mr Matthies,
you have a very good way of discussing things.

Note that the only consequence of passing a zero length is that you
receive a negative result. Nothing else happens, and you are
free to ignore the result...

Dec 3 '06 #9

P: n/a
On 2006-12-03 19:39, jacob navia wrote:
:
The straw man argument consists of making others believe that your
adversary has said something ridiculous, and absolutely absurd.

You take also a sentence where I say:

"What's the point of reading a line of zero length?"
So, what's the point of adding zero to an integer?

-- Niklas Matthies
Dec 3 '06 #10

P: n/a
On Sun, 03 Dec 2006 20:39:39 +0100, in comp.lang.c , jacob navia
<ja***@jacob.remcomp.frwrote:
>
The straw man argument consists of making others believe that your
adversary has said something ridiculous, and absolutely absurd.
indeed, and its something you seem quite fond of.
>
You take also a sentence where I say:

"What's the point of reading a line of zero length?"

to mean that I am against additions... How nice Mr Matthies,
you have a very good way of discussing things.
case in point. Niklas dids not say that.
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Dec 3 '06 #11

P: n/a
pete <pf*****@mindspring.comwrites:
jacob navia wrote:
[...]
>-4 Line pointer points to a buffer but n is <= 0. This is an error in
the incoming arguments.

Not if the buffer is allocated this way:
n = 0;
buffer = malloc(0);
[...]

The result of malloc(0) is implementation-defined; it can either
return a null pointer or a pointer to some allocated but inaccessible
memory. C doesn't support zero-sized objects.

If it did, though, it would make sense to support them in all possible
contexts, just for the sake of consistency. It's dangerous to assume
that nobody would ever use a function in some particular way.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Dec 3 '06 #12

P: n/a
On 2006-12-03 21:49, Keith Thompson wrote:
pete <pf*****@mindspring.comwrites:
>jacob navia wrote:
[...]
>>-4 Line pointer points to a buffer but n is <= 0. This is an error in
the incoming arguments.

Not if the buffer is allocated this way:
n = 0;
buffer = malloc(0);
[...]

The result of malloc(0) is implementation-defined; it can either
return a null pointer or a pointer to some allocated but
inaccessible memory.
Which means you can use it portably as if it were a pointer to a
zero-sized object (as long as you don't expect it to have a unique
address, that is).
C doesn't support zero-sized objects. If it did, though, it would
make sense to support them in all possible contexts, just for the
sake of consistency.
Given the above, it already does make sense.

-- Niklas Matthies
Dec 3 '06 #13

P: n/a
Niklas Matthies <us***********@nmhq.netwrites:
On 2006-12-03 21:49, Keith Thompson wrote:
>pete <pf*****@mindspring.comwrites:
>>jacob navia wrote:
[...]
>>>-4 Line pointer points to a buffer but n is <= 0. This is an error in
the incoming arguments.

Not if the buffer is allocated this way:
n = 0;
buffer = malloc(0);
[...]

The result of malloc(0) is implementation-defined; it can either
return a null pointer or a pointer to some allocated but
inaccessible memory.

Which means you can use it portably as if it were a pointer to a
zero-sized object (as long as you don't expect it to have a unique
address, that is).
Any standard library function with a char* parameter that points to a
string invokes undefined behavior if the argument is a null pointer.

char *s = malloc(0);
size_t len = strlen(s);
/*
* Returns 0 if s != NULL
* Invokes UB if s == NULL
*/

A valid string has to have a size of at least 1, but consider also the
mem*() functions.
>C doesn't support zero-sized objects. If it did, though, it would
make sense to support them in all possible contexts, just for the
sake of consistency.

Given the above, it already does make sense.
I disagree.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Dec 3 '06 #14

P: n/a
Keith Thompson wrote:
>
Any standard library function with a char* parameter that points to a
string invokes undefined behavior if the argument is a null pointer.
Well, "almost any." Two counterexamples are strtok()
and system().

--
Eric Sosman
es*****@acm-dot-org.invalid
Dec 3 '06 #15

P: n/a
Eric Sosman <es*****@acm-dot-org.invalidwrites:
Keith Thompson wrote:
>Any standard library function with a char* parameter that points to a
string invokes undefined behavior if the argument is a null pointer.

Well, "almost any." Two counterexamples are strtok()
and system().
You're right, of course.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Dec 3 '06 #16

P: n/a
["Followup-To:" header set to comp.std.c.]
On 2006-12-03 22:36, Keith Thompson wrote:
Niklas Matthies <us***********@nmhq.netwrites:
>On 2006-12-03 21:49, Keith Thompson wrote:
:
>>The result of malloc(0) is implementation-defined; it can either
return a null pointer or a pointer to some allocated but
inaccessible memory.

Which means you can use it portably as if it were a pointer to a
zero-sized object (as long as you don't expect it to have a unique
address, that is).

Any standard library function with a char* parameter that points to a
string invokes undefined behavior if the argument is a null pointer.
:
A valid string has to have a size of at least 1, but consider also
the mem*() functions.
Strings are never zero-sized objects for the reason you note, hence
pretty irrelevant to the discussion, but for functions that work on
raw memory, like the mem* functions or fread/fwrite, it would make
perfectly sense to allow whatever malloc(0) returns when the buffer
size is zero.

-- Niklas Matthies
Dec 3 '06 #17

P: n/a

On Sun, 3 Dec 2006, Keith Thompson wrote:
Niklas Matthies <us***********@nmhq.netwrites:
>On 2006-12-03 21:49, Keith Thompson wrote:
>>>
The result of malloc(0) is implementation-defined; it can either
return a null pointer or a pointer to some allocated but
inaccessible memory.

Which means you can use it portably as if it were a pointer to a
zero-sized object (as long as you don't expect it to have a unique
address, that is).

Any standard library function with a char* parameter that points to a
string invokes undefined behavior if the argument is a null pointer.

char *s = malloc(0);
size_t len = strlen(s);
/*
* Returns 0 if s != NULL
* Invokes UB if s == NULL
*/
ITYM "Invokes UB if s == malloc(0)". Whether s is a null pointer, or
simply points to zero bytes of memory, trying to access s[0] will invoke
undefined behavior. So there's no difference between NULL and (unnamed
zero-sized object) /in this case/.
A valid string has to have a size of at least 1, but consider also the
mem*() functions.
Yes. This is the example you should have used. (7.1.4 says that NULL
is not a "valid value" for pointer arguments to functions, and 7.21.1#2
says that string functions require valid values as arguments.)

-Arthur
Dec 3 '06 #18

P: n/a
jacob navia wrote:
Niklas Matthies a crit :
>On 2006-12-03 12:53, jacob navia wrote:
>>pete a crit :

jacob navia wrote:

:
>>>Not if the buffer is allocated this way:
n = 0;
buffer = malloc(0);

This is ridiculous... Now what is the point of getting a line of zero
length???? This is surely an error!


Following your logic,

int n = 0;
...
int k = m + n;

is surely an error as well (better raise a signal or something),
and one should write

int k = m;
if (n != 0)
{
k += n;
}

instead...

The straw man argument consists of making others believe that your
adversary has said something ridiculous, and absolutely absurd.
You do not seem to have expended enough effort to interpret what mr.
Matthies was saying. He was attempting to discredit the logic of your
decision by using an analogous situation which you would obviously not be
tempted to declare erroneous.
You take also a sentence where I say:

"What's the point of reading a line of zero length?"

to mean that I am against additions... How nice Mr Matthies,
you have a very good way of discussing things.
He was trying to point out that it makes sense to allow operations that have
no effect, despite the fact that they have no effect. It should not be
considered an error because it may arise naturally in an algorithm, and
treating it as an error complifies algorithm design by requiring the
programmer to distinguish a special case. In short, that you do not see the
"point" of something is not sufficient reason to declare it an error.

S.
Dec 4 '06 #19

P: n/a
jacob navia <ja***@jacob.remcomp.frwrote:
ssize_t getdelim(char **restrict lineptr,
size_t *restrict n, int delimiter, FILE *stream);
< quote >

Upon successful completion the getdelim function shall return the number
of characters written into the buffer, including the delimiter character
if one was encountered before EOF. Otherwise it shall return −1.

< end quote >

We come back here to the error analysis problem, a problem that I
have been mentioning since ages and comes again and again. Returning
-1 to indicate "some error occurred but I will not tell you which"
is BAD DESIGN!
True. But so is...
Lcc-win32 implements this function and returns:

-5 No memory left for allocating the line
-4 Line pointer points to a buffer but n is <= 0. This is an error in
the incoming arguments.
-3 The n parameter is NULL
-2 The LinePointer parameter is NULL
-1 End of file without any characters read.
....this.

You have been given errno by the Standard. Use it.

Richard
Dec 5 '06 #20

P: n/a
Richard Bos a crit :
jacob navia <ja***@jacob.remcomp.frwrote:

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

>>< quote >

Upon successful completion the getdelim function shall return the number
of characters written into the buffer, including the delimiter character
if one was encountered before EOF. Otherwise it shall return −1.

< end quote >

We come back here to the error analysis problem, a problem that I
have been mentioning since ages and comes again and again. Returning
-1 to indicate "some error occurred but I will not tell you which"
is BAD DESIGN!


True. But so is...

>>Lcc-win32 implements this function and returns:

-5 No memory left for allocating the line
-4 Line pointer points to a buffer but n is <= 0. This is an error in
the incoming arguments.
-3 The n parameter is NULL
-2 The LinePointer parameter is NULL
-1 End of file without any characters read.


...this.

You have been given errno by the Standard. Use it.

Richard
The problems of errno are many... You have to avoid forgetting to
set it to zero before calling the function, and it is an ugly global
variable. Why is a result value a bad design? Can you explain?
Dec 5 '06 #21

P: n/a
jacob navia wrote:
The problems of errno are many... You have to avoid forgetting to
set it to zero before calling the function, and it is an ugly global
variable. Why is a result value a bad design? Can you explain?
HPUX 11.0:
extern int *__errno(void);
#define errno (*__errno())

Solaris 7:
#if (defined(_REENTRANT) || defined(_TS_ERRNO) || \
_POSIX_C_SOURCE - 0 >= 199506L) && !(defined(lint) ||
defined(__lint))
extern int *___errno();
#define errno (*(___errno()))
....

And similar on Linux & others I believe. Of course, it _can_ as well be
a global variable...

--
WYCIWYG - what you C is what you get

Dec 5 '06 #22

P: n/a
matevzb a crit :
jacob navia wrote:
>>The problems of errno are many... You have to avoid forgetting to
set it to zero before calling the function, and it is an ugly global
variable. Why is a result value a bad design? Can you explain?


HPUX 11.0:
extern int *__errno(void);
#define errno (*__errno())

Solaris 7:
#if (defined(_REENTRANT) || defined(_TS_ERRNO) || \
_POSIX_C_SOURCE - 0 >= 199506L) && !(defined(lint) ||
defined(__lint))
extern int *___errno();
#define errno (*(___errno()))
...

And similar on Linux & others I believe. Of course, it _can_ as well be
a global variable...

--
WYCIWYG - what you C is what you get
And in lcc-win32 too. What's the point?

The fact that it calls a function that reads a global variable that
is thread specific (the reson for this) doesn't change the fact
that errno is a global variable.
Dec 5 '06 #23

P: n/a
jacob navia wrote:
matevzb a crit :
jacob navia wrote:
>The problems of errno are many... You have to avoid forgetting to
set it to zero before calling the function, and it is an ugly global
variable. Why is a result value a bad design? Can you explain?
<snip>
And in lcc-win32 too. What's the point?
The point is purely "semantic". You said "it is an ugly global
variable" which may or may not be true. It can be a
function-calling-macro to access an ugly global variable.
The fact that it calls a function that reads a global variable that
is thread specific (the reson for this) doesn't change the fact
that errno is a global variable.
Agreed, except for what was mentioned above. No offense meant. =)

--
WYCIWYG - what you C is what you get

Dec 5 '06 #24

P: n/a
jacob navia wrote:
matevzb a crit :
jacob navia wrote:
>The problems of errno are many... You have to avoid forgetting to
set it to zero before calling the function, and it is an ugly global
variable. Why is a result value a bad design? Can you explain?

HPUX 11.0:
extern int *__errno(void);
#define errno (*__errno())

Solaris 7:
#if (defined(_REENTRANT) || defined(_TS_ERRNO) || \
_POSIX_C_SOURCE - 0 >= 199506L) && !(defined(lint) ||
defined(__lint))
extern int *___errno();
#define errno (*(___errno()))
...

And similar on Linux & others I believe. Of course, it _can_ as well be
a global variable...

--
WYCIWYG - what you C is what you get

And in lcc-win32 too. What's the point?

The fact that it calls a function that reads a global variable that
is thread specific (the reson for this) doesn't change the fact
that errno is a global variable.
No, errno is a macro that, for those implementations, expands into a
dereferencing of the pointer value returned by a function call. The
variable referred to by dereferencing that pointer value is not
required to be global, nor is it required to have the name "errno". It
could be dynamically allocated, or a file-scope or even block-scope
static variable. I'm not very familiar with multi-threaded programming
environment, but I'm sure that all three of those are legal
possibilities in a single-threaded environment.

However, your basic point is correct - errno's defined semantics are
such that, at least in a single-threaded environment, it can be
implemented as a global variable. That means that it possesses most of
the design problems that it would have if it were required to be a
global variable.

Dec 5 '06 #25

P: n/a

[fups-to: comp.std.c, comp.compilers.lcc]

On Tue, 5 Dec 2006, jacob navia wrote:
Richard Bos a crit :
>jacob navia <ja***@jacob.remcomp.frwrote:
>>>
ssize_t getdelim(char **restrict lineptr,
size_t *restrict n, int delimiter, FILE *stream);

We come back here to the error analysis problem, a problem that I
have been mentioning since ages and comes again and again. Returning
-1 to indicate "some error occurred but I will not tell you which"
is BAD DESIGN!

True. But so is...
>>>
-5 No memory left for allocating the line
-4 Line pointer points to a buffer but n is <= 0. This is an error in
the incoming arguments.
-3 The n parameter is NULL
-2 The LinePointer parameter is NULL
-1 End of file without any characters read.

You have been given errno by the Standard. Use it.

The problems of errno are many... You have to avoid forgetting to
set it to zero before calling the function, and it is an ugly global
variable. Why is a result value a bad design? Can you explain?
IMNSHO, errno is awful and should not be used in new code, for the
reasons Jacob mentions. However, Jacob replaces it with a collection of
five different magic numbers that can be returned by just one function;
this solution clearly can't scale!

switch (myfunc()) {
case -5:
case -4:
handle_one(); break;
case -3:
handle_two(); break;
[...]

Would code with this many magic numbers pass /your/ code reviews? A
slightly better idea would be to give them mnemonic names --- perhaps even
reusing the implementation's errno macros (EINVAL, ENOMEM, whatever). This
might require standardizing more of those identifiers; I know only a few
of them are standard, despite the entire E* namespace's being reserved.

So Jacob's solution is bad, but it's the lesser of two evils. OTOH, I'm
not yet convinced there's not a third evil that's lessest! ;)

my $.02,
-Arthur
Dec 5 '06 #26

P: n/a
jacob navia wrote:
>We come back here to the error analysis problem, a problem that I
have been mentioning since ages and comes again and again. Returning
-1 to indicate "some error occurred but I will not tell you which"
is BAD DESIGN!
Richard Bos wrote:
>You have been given errno by the Standard. Use it.
jacob navia wrote:
The problems of errno are many... You have to avoid forgetting to
set it to zero before calling the function, and it is an ugly global
variable. Why is a result value a bad design? Can you explain?
Can you guarantee that the function will never return any of
the error values as non-errors? I.e., given that the return code
is signed (which it needs to be because of the error values),
is there a guarantee that the function will never return a
large (unsigned) success value that gets converted into a
small signed value?

Furthermore, if we assume that only values between -1 and,
say, -9 are error values, what happens to our code when we
need to add another error value to the function in the next
revision?

And where are the macros for those magic return values?

Using errno properly is not that difficult, and it works.

-drt

Dec 5 '06 #27

P: n/a
"Hallvard B Furuseth" <h.**********@usit.uio.nowrote in message
news:hb**************@bombur.uio.no...
jacob navia writes:
>... is BAD DESIGN!
Indeed. Why don't they just set errno though? ...
Guys, it's a *working draft*. There is still time to improve the specs,
but that's not going to happen by you squawking here. Provide
useful comments back to the draft's editor.
Dec 6 '06 #28

P: n/a
Douglas A. Gwyn a crit :
"Hallvard B Furuseth" <h.**********@usit.uio.nowrote in message
news:hb**************@bombur.uio.no...
>>jacob navia writes:
>>>... is BAD DESIGN!

Indeed. Why don't they just set errno though? ...


Guys, it's a *working draft*. There is still time to improve the specs,
but that's not going to happen by you squawking here. Provide
useful comments back to the draft's editor.

Oooops!

I was supposing that the author(s) read this newsgroup, what may be
untrue. Reading the document there is no obvious hint as to
who edited or who proposed it. In the link that leads to that document
there is the mention:
2006/10/03 Stoughton, Specification for C Library Functions - Part 2:
Dynamic Allocation Functions.

Maybe you know how to contact (Mr or Mrs) Stoughton ?
(E-mail, or address)

Thanks

jacob
Dec 6 '06 #29

P: n/a
On Wed, 06 Dec 2006 09:49:53 +0100, in comp.lang.c , jacob navia
<ja***@jacob.remcomp.frwrote:
>Maybe you know how to contact (Mr or Mrs) Stoughton ?
(E-mail, or address)
STFW.

"Stoughton" (probably Nick) is an ISO/IEC committee member
representing the FSG, so presumably you can contact the WG14 or the
FSG.
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Dec 6 '06 #30

P: n/a
jacob navia <ja***@jacob.remcomp.frwrote:
Richard Bos a crit :
jacob navia <ja***@jacob.remcomp.frwrote:
>Lcc-win32 implements this function and returns:

-5 No memory left for allocating the line
-4 Line pointer points to a buffer but n is <= 0. This is an error in
the incoming arguments.
-3 The n parameter is NULL
-2 The LinePointer parameter is NULL
-1 End of file without any characters read.
...this.

You have been given errno by the Standard. Use it.

The problems of errno are many... You have to avoid forgetting to
set it to zero before calling the function, and it is an ugly global
variable.
All true. However, it has one great advantage: it is Standard ISO C, and
therefore known to all users and predictable.
Why is a result value a bad design? Can you explain?
_A_ result value is not. Using random negative values for errors and
positive values for non-errors is fragile. It presumes that correct
results will never overflow into negative values, for example. _If_ you
know that this will never happen, that's fine, but this function is
meant as an enhancement to the Standard, not as part of a single program
with predictable input, so it needs to be more solid than most.

For the record: I have nothing against your solution _for a user
function_. For a (meant to become Standard) library function, though, I
strongly suggest using the Standard mechanism for reporting errors.

Richard
Dec 8 '06 #31

P: n/a
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.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 8 '06 #32

P: n/a
Richard Heathfield wrote:
>
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.
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.

--
pete
Dec 8 '06 #33

P: n/a
Richard Bos wrote:
jacob navia <ja***@jacob.remcomp.frwrote:
.... snip ..
>
>Why is a result value a bad design? Can you explain?

_A_ result value is not. Using random negative values for errors
and positive values for non-errors is fragile. It presumes that
correct results will never overflow into negative values, for
example. _If_ you know that this will never happen, that's fine,
but this function is meant as an enhancement to the Standard, not
as part of a single program with predictable input, so it needs
to be more solid than most.

For the record: I have nothing against your solution _for a user
function_. For a (meant to become Standard) library function,
though, I strongly suggest using the Standard mechanism for
reporting errors.
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. Success is always reported by zero, leaving the
full integer range for various errors. This interfaces easily with
any routine to read as much as is available:

while (!ggets(&lineptr)) processline(lineptr);

and if you want to differentiate between failures you just save the
return value. This is also why ggets doesn't return the line
length. The complications of using ERRNO would be indescribable.
KISS applies. Save the complications for the rare cases.

<http://cbfalconer.home.att/download/>

BTW Jacobs routine has the fault of returning -1 for EOF, which may
or may not agree with the system. This forces detailed reading of
the routine specification, and/or publishing an enom of values for
the various errors, which may in turn lead to name conflicts.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Dec 8 '06 #34

P: n/a
CBFalconer said:
<http://cbfalconer.home.att/download/>
An error occured while loading http://cbfalconer.home.att/:

Unknown host cbfalconer.home.att
Is that a temporary problem with the server, or a typo in the name
somewhere?

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 8 '06 #35

P: n/a
Richard Heathfield wrote:
CBFalconer said:
<http://cbfalconer.home.att/download/>

An error occured while loading http://cbfalconer.home.att/:

Unknown host cbfalconer.home.att
Is that a temporary problem with the server, or a typo in the name
somewhere?
His sig. contains the correct URL. The .net suffix is missing.

Dec 8 '06 #36

P: n/a
Richard Heathfield <rj*@see.sig.invalidwrites:
CBFalconer said:
> <http://cbfalconer.home.att/download/>

An error occured while loading http://cbfalconer.home.att/:

Unknown host cbfalconer.home.att
Last time I checked, ".att" isn't a top-level domain.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Dec 8 '06 #37

P: n/a
Richard Heathfield wrote:
CBFalconer said:
<http://cbfalconer.home.att/download/>

An error occured while loading http://cbfalconer.home.att/:

Unknown host cbfalconer.home.att

Is that a temporary problem with the server, or a typo in the name
somewhere?
Typo. Try <http://cbfalconer.home.att.net/download/>

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Dec 8 '06 #38

P: n/a
Richard Bos said:
>However, [errno] has one great advantage: it is Standard ISO C,
Richard Heathfield wrote:
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.
Sorry, but I'm not going to stop writing portable code that uses errno
just because one implementation gets it wrong.

-drt

Dec 10 '06 #39

P: n/a
David R Tribble said:
Richard Bos said:
>>However, [errno] has one great advantage: it is Standard ISO C,

Richard Heathfield wrote:
>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.

Sorry, but I'm not going to stop writing portable code that uses errno
just because one implementation gets it wrong.
Understood. But I did precisely that, because I *needed* my stuff to compile
under that implementation (among others).

If you don't have to port to <foo>, there's no need to make your stuff
<foo>-compatible. But if you do, you have no choice. Which is why I don't
use errno at all - and that's a bit of a pest when it comes to robust use
of, say, strtol.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 10 '06 #40

P: n/a
Richard Heathfield <rj*@see.sig.invalidwrites:
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?

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Dec 10 '06 #41

P: n/a
Keith Thompson said:
Richard Heathfield <rj*@see.sig.invalidwrites:
>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!

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.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 11 '06 #42

P: n/a
pete <pf*****@mindspring.comwrote:
Richard Heathfield wrote:

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.

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
Dec 11 '06 #43

P: n/a
Richard Heathfield wrote:
Keith Thompson said:
Richard Heathfield <rj*@see.sig.invalidwrites:
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.

Dec 11 '06 #44

P: n/a
santosh said:

<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.
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?

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 11 '06 #45

P: n/a
Richard Heathfield wrote:
santosh said:

<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.

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.

Dec 11 '06 #46

P: n/a
Harald van Dijk wrote:
Richard Heathfield wrote:
santosh said:

<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.
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 <string.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.
Sorry about that.

Dec 11 '06 #47

P: n/a

Richard Bos wrote:
pete <pf*****@mindspring.comwrote:
[...]

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.
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.''

Dec 11 '06 #48

P: n/a
Harald van D?k said:
Richard Heathfield wrote:
>santosh said:

<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.

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,
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.)

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 11 '06 #49

P: n/a

Richard Heathfield wrote:
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.

Dec 11 '06 #50

61 Replies

This discussion thread is closed

Replies have been disabled for this discussion.