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

questions on ftell and fopen

P: n/a
Consider the following program:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: <program-name<text-file>\n");
exit(EXIT_FAILURE);
}

FILE *fp;

if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("Could not open input file :%s:\n", argv[1]);
exit(EXIT_FAILURE);
}

if (fseek(fp, 0L, SEEK_END) == 0)
printf("fseek successful\n");
else
printf("fseek failed\n");

long int size = ftell(fp);

printf("filesize = %ld\n", size);

fclose(fp);

char a[size+1];
a[size] = '\0';

if ((fp = fopen(argv[1], "rb")) == NULL)
{
printf("Could not open input file :%s:\n", argv[1]);
exit(EXIT_FAILURE);
}

fread(a, size, 1, fp);

if (ferror(fp))
{
printf("fread failed\n");
fclose(fp);
exit(EXIT_FAILURE);
}

fclose(fp);

printf("%s", a);

return 0;
}

Suppose the name of the file is tmp.c

I compiled this program with gcc under Redhat Enterprise Linux with
the command

gcc -std=c99 tmp.c

It compiles well. I ran it with the command

$./a.out tmp.c

It runs successfully.

My questions:
1) Is the usage of ftell above correct ?
2) In the second fopen, I have used "rb" for the mode ie I am opening
the text file in binary mode and then using fread. Will this always
work ?

Mar 2 '07 #1
Share this Question
Share on Google+
25 Replies


P: n/a
Sorry for the inconvenience.

The first question should be
1)Can I use fseek for a text stream as used in this program(though it
seems to work)

Mar 2 '07 #2

P: n/a
"su**************@yahoo.com, India" <su**************@yahoo.com>
writes:
1)Can I use fseek for a text stream as used in this program(though it
seems to work)
Your use of fseek is like this:
if (fseek(fp, 0L, SEEK_END) == 0)
This is fine for use with a text stream (as you use it).
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}
Mar 2 '07 #3

P: n/a
Hello,

Kindly answer my second question also.

Thanks

Mar 2 '07 #4

P: n/a
On 2 Mar, 05:52, "subramanian10...@yahoo.com, India"
<subramanian10...@yahoo.comwrote:
Consider the following program:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: <program-name<text-file>\n");
exit(EXIT_FAILURE);
}

FILE *fp;

if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("Could not open input file :%s:\n", argv[1]);
exit(EXIT_FAILURE);
}

if (fseek(fp, 0L, SEEK_END) == 0)
printf("fseek successful\n");
else
printf("fseek failed\n");

long int size = ftell(fp);

printf("filesize = %ld\n", size);

fclose(fp);

char a[size+1];
a[size] = '\0';

if ((fp = fopen(argv[1], "rb")) == NULL)
{
printf("Could not open input file :%s:\n", argv[1]);
exit(EXIT_FAILURE);
}

fread(a, size, 1, fp);

if (ferror(fp))
{
printf("fread failed\n");
fclose(fp);
exit(EXIT_FAILURE);
}

fclose(fp);

printf("%s", a);

return 0;

}

Suppose the name of the file is tmp.c

I compiled this program with gcc under Redhat Enterprise Linux with
the command

gcc -std=c99 tmp.c

It compiles well. I ran it with the command

$./a.out tmp.c

It runs successfully.

My questions:
FAQ 12.40 et al http://c-faq.com/stdio/textvsbinary.html
1) Is the usage of ftell above correct ?
No - from the FAQ :-
"Text mode translations also affect the apparent size of a file as
it's read. Because the characters read from and written to a file in
text mode do not necessarily match the characters stored in the file
exactly, the size of the file on disk may not always match the number
of characters which can be read from it. Furthermore, for analogous
reasons, the fseek and ftell functions do not necessarily deal in pure
byte offsets from the beginning of the file. (Strictly speaking, in
text mode, the offset values used by fseek and ftell should not be
interpreted at all: a value returned by ftell should only be used as a
later argument to fseek, and only values returned by ftell should be
used as arguments to fseek.)"
2) In the second fopen, I have used "rb" for the mode ie I am opening
the text file in binary mode and then using fread. Will this always
work ?
Yes - read the FAQ.

However reading it into a buffer sized by fseek/ftell on a stream
opened in text mode is asking for trouble.

Mar 2 '07 #5

P: n/a
su**************@yahoo.com, India wrote, On 02/03/07 05:52:
Consider the following program:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: <program-name<text-file>\n");
exit(EXIT_FAILURE);
}

FILE *fp;

if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("Could not open input file :%s:\n", argv[1]);
exit(EXIT_FAILURE);
}

if (fseek(fp, 0L, SEEK_END) == 0)
printf("fseek successful\n");
else
printf("fseek failed\n");

long int size = ftell(fp);

printf("filesize = %ld\n", size);
This does not portably determine the size of a file. Read question 19.12
of the comp.lang.c FAQ which you can find at http://c-faq.com/
fclose(fp);

char a[size+1];
a[size] = '\0';

if ((fp = fopen(argv[1], "rb")) == NULL)
{
printf("Could not open input file :%s:\n", argv[1]);
exit(EXIT_FAILURE);
}

fread(a, size, 1, fp);
Note in particular that some common systems use two bytes to indicate
the end of a line, will it count those as 1 or 2 bytes in the result
returned by ftell?
if (ferror(fp))
{
printf("fread failed\n");
fclose(fp);
exit(EXIT_FAILURE);
}

fclose(fp);

printf("%s", a);

return 0;
}

Suppose the name of the file is tmp.c

I compiled this program with gcc under Redhat Enterprise Linux with
the command

gcc -std=c99 tmp.c

It compiles well. I ran it with the command

$./a.out tmp.c

It runs successfully.

My questions:
1) Is the usage of ftell above correct ?
No, it is not guaranteed to return the byte count on text files.
2) In the second fopen, I have used "rb" for the mode ie I am opening
the text file in binary mode and then using fread. Will this always
work ?
I cannot think of a reason for it not to work on *nix, but there is
nothing to stop some system having a text/binary attribute and refusing
to open text files in binary mode or binary files in text mode, on such
a system one of your fopen calls would always fail, which one depending
on the type of the file.

In addition, reading a file in binary mode then printing it out in text
mode could have strange effects. On a Windows system, you would be
likely to find that each end-of-line CRLR read would be printed as
CRCRLF, and on MacOS9 or earlier you would have different, and possibly
stranger, effects.

Also, who says you will have enough memory to lead the entire file? The
system I'm working with frequently has files approaching 2GB (including
text files, and once everyone is on modern file systems we will probably
allow them to grow even larger.
--
Flash Gordon
Mar 2 '07 #6

P: n/a
"su**************@yahoo.com, India" wrote:
>
Kindly answer my second question also.
I see no second question. In fact I see no first question. See
the following sig and link.

--
If you want to post a followup via groups.google.com, ensure
you quote enough for the article to make sense. Google is only
an interface to Usenet; it's not Usenet itself. Don't assume
your readers can, or ever will, see any previous articles.
More details at: <http://cfaj.freeshell.org/google/>
Mar 2 '07 #7

P: n/a
CBFalconer <cb********@maineline.netwrote:
If you want to post a followup via groups.google.com, ensure
you quote enough
*Just* enough! :)

-Beej

Mar 3 '07 #8

P: n/a
On Mar 2, 5:52 am, "subramanian10...@yahoo.com, India"
<subramanian10...@yahoo.comwrote:
Consider the following program:
<some code snipped>
>
if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("Could not open input file :%s:\n", argv[1]);
exit(EXIT_FAILURE);
}
Just a note, you may be much happier replacing the printf line with:
perror(argv[1]);
It will print a much more meaningful message. eg:
[tmp]$ ./a.out foo
foo: No such file or directory
[tmp]$ touch foo; chmod 000 foo; ./a.out foo
foo: Permission denied
>
if (fseek(fp, 0L, SEEK_END) == 0)
printf("fseek successful\n");
else
printf("fseek failed\n");
Again here. Don't use printf, use perror, as it
will tell you the reason for the error.
>
long int size = ftell(fp);

printf("filesize = %ld\n", size);
This may be a philosophical complaint, but this
is totally bogus. It's like going to the mouth
of a river, computing the distance to the headwaters
and claiming that you can derive the amount of
water in the river from that information. "How
much water is in the river?" is simply a non-sensical
question. There are some files for which it makes sense,
but in the strict sense of the C standard, asking for
the size of a file is simply an absurd question.
Files are streams. If you have a "regular file" (which
is outside the scope of the C standard), then the
correct way to determine its size is system specific.
Since you've said you're on Linux, you should use fstat().

My questions:
1) Is the usage of ftell above correct ?
In a philosophical sense, no.
2) In the second fopen, I have used "rb" for the mode ie I am opening
the text file in binary mode and then using fread. Will this always
work ?
Since you indicate that you ran this on a linux box: consider this
from the documentation:

The mode string can also include the letter ''b'' either as
a last character or as a character between the characters in
any of the two-character strings described above. This is
strictly for compatibility with ANSI X3.159-1989 (''ANSI C'')
and has no effect; the ''b'' is ignored on all POSIX conforming
systems, including Linux.

--
Bill Pursell

Mar 3 '07 #9

P: n/a
"Bill Pursell" <bi**********@gmail.comwrites:
On Mar 2, 5:52 am, "subramanian10...@yahoo.com, India"
<subramanian10...@yahoo.comwrote:
>Consider the following program:
<some code snipped>
>>
if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("Could not open input file :%s:\n", argv[1]);
exit(EXIT_FAILURE);
}

Just a note, you may be much happier replacing the printf line with:
perror(argv[1]);
It will print a much more meaningful message. eg:
[tmp]$ ./a.out foo
foo: No such file or directory
[tmp]$ touch foo; chmod 000 foo; ./a.out foo
foo: Permission denied
It's likely to do so on most systems, but the standard doesn't
actually guarantee that a failing fopen() sets errno.

[...]
> long int size = ftell(fp);

printf("filesize = %ld\n", size);

This may be a philosophical complaint, but this
is totally bogus. It's like going to the mouth
of a river, computing the distance to the headwaters
and claiming that you can derive the amount of
water in the river from that information. "How
much water is in the river?" is simply a non-sensical
question.
Not a great example. "How much water is in the river?" is a sensible
question with a definite answer; computing the distance to the
headwaters just isn't a good way to measure it.

The "size" of a file, on the other hand, may or may not be a
meaningful concept, depending on the file and the OS. A plain file on
a Unix-like system does have a meaningful size, and the fseek/ftell
trick should give it to you accurately (if it doesn't exceed LONG_MAX
bytes); calling fgetc() in a loop and counting characters will give
you the same result, but much more slowly.

But for non-plain files, or for files on other systems, these
techniques may give you inconsistent results, or may not work at all.
The C standard wisely doesn't require Unix-like semantics, so there is
no portable way to determine the "size" of a file.

If you want to know the size of a file, first ask yourself exactly
what that means, and why you want to know it.

--
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."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Mar 3 '07 #10

P: n/a
On Mar 3, 8:06 pm, Keith Thompson <k...@mib.orgwrote:
"Bill Pursell" <bill.purs...@gmail.comwrites:
On Mar 2, 5:52 am, "subramanian10...@yahoo.com, India"
<subramanian10...@yahoo.comwrote:
Consider the following program:
<some code snipped>
if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("Could not open input file :%s:\n", argv[1]);
exit(EXIT_FAILURE);
}
Just a note, you may be much happier replacing the printf line with:
perror(argv[1]);
It will print a much more meaningful message. eg:
[tmp]$ ./a.out foo
foo: No such file or directory
[tmp]$ touch foo; chmod 000 foo; ./a.out foo
foo: Permission denied

It's likely to do so on most systems, but the standard doesn't
actually guarantee that a failing fopen() sets errno.
True. However, it strikes me that it is NOT the
programmer's responsibility to account for inadequacies
of the implementation.

--
Bill Pursell

Mar 4 '07 #11

P: n/a
Bill Pursell wrote, On 04/03/07 06:57:
On Mar 3, 8:06 pm, Keith Thompson <k...@mib.orgwrote:
<snip>
>It's likely to do so on most systems, but the standard doesn't
actually guarantee that a failing fopen() sets errno.

True. However, it strikes me that it is NOT the
programmer's responsibility to account for inadequacies
of the implementation.
Wrong IMHO. It is the programmer's responsibility to produce software
that works correctly on whatever system the customer wants even if the C
implementation on that system is completely useless. Of course, if you
are prepared to pay compensation for the loss of one of my companies
biggest customers because you think we should not allow for the
inadequacies of their chosen system I will happily stop jumping through
the required hoops to support it.
--
Flash Gordon
Mar 4 '07 #12

P: n/a
On Mar 4, 11:13 am, Flash Gordon <s...@flash-gordon.me.ukwrote:
Bill Pursell wrote, On 04/03/07 06:57:
On Mar 3, 8:06 pm, Keith Thompson <k...@mib.orgwrote:

<snip>
It's likely to do so on most systems, but the standard doesn't
actually guarantee that a failing fopen() sets errno.
True. However, it strikes me that it is NOT the
programmer's responsibility to account for inadequacies
of the implementation.

Wrong IMHO. It is the programmer's responsibility to produce software
that works correctly on whatever system the customer wants even if the C
implementation on that system is completely useless.
So how do you deal with it? Do you write a wrapper like the
following around every libc function that the standard doesn't
require to set errno? It seems rather kludgy.
#include <stdio.h>

void
report_fopen_error( const char * path )
{
#ifdef FOPEN_SETS_ERRNO
perror( path );
#else
const char *format = "unable to open %s: reason unkown. %s\n";
const char *smarmy_remark = "Upgrade your box.";
fprintf( stderr, format, path, smarmy_remark);
#endif
}
--
Bill Pursell

Mar 4 '07 #13

P: n/a
"Bill Pursell" <bi**********@gmail.comwrites:
On Mar 4, 11:13 am, Flash Gordon <s...@flash-gordon.me.ukwrote:
>Bill Pursell wrote, On 04/03/07 06:57:
On Mar 3, 8:06 pm, Keith Thompson <k...@mib.orgwrote:
It's likely to do so on most systems, but the standard doesn't
actually guarantee that a failing fopen() sets errno.
True. However, it strikes me that it is NOT the
programmer's responsibility to account for inadequacies
of the implementation.

Wrong IMHO. It is the programmer's responsibility to produce software
that works correctly on whatever system the customer wants even if the C
implementation on that system is completely useless.

So how do you deal with it? [...]
You can save a copy of errno and set errno to 0 before calling
fopen, then on fopen failure only print a message based on errno
if errno is nonzero.

Most code that I've seen doesn't try this hard.
--
"Your correction is 100% correct and 0% helpful. Well done!"
--Richard Heathfield
Mar 4 '07 #14

P: n/a
"Bill Pursell" <bi**********@gmail.comwrites:
On Mar 3, 8:06 pm, Keith Thompson <k...@mib.orgwrote:
>"Bill Pursell" <bill.purs...@gmail.comwrites:
On Mar 2, 5:52 am, "subramanian10...@yahoo.com, India"
<subramanian10...@yahoo.comwrote:
Consider the following program:
<some code snipped>
> if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("Could not open input file :%s:\n", argv[1]);
exit(EXIT_FAILURE);
}
Just a note, you may be much happier replacing the printf line with:
perror(argv[1]);
It will print a much more meaningful message. eg:
[tmp]$ ./a.out foo
foo: No such file or directory
[tmp]$ touch foo; chmod 000 foo; ./a.out foo
foo: Permission denied

It's likely to do so on most systems, but the standard doesn't
actually guarantee that a failing fopen() sets errno.

True. However, it strikes me that it is NOT the
programmer's responsibility to account for inadequacies
of the implementation.
Yes, it is. Whose responsibility do you think it is?

A standard is a contract between the implementer and the programmer.
If an implementer claims his compiler conforms to the C standard, the
programmer may reasonably rely on that claim and make use of any
features guaranteed by the standard. If the programmer relies on
something *not* guaranteed by the standard (in this case, that fopen()
sets errno on failure), and the program misbehaves as a result, who is
responsible for the failure?

On the other hand, another standard might provide additional
guarantees. POSIX, for example, requires fopen() to set errno on
failure. If an implementer claims conformance to POSIX as well as to
the C standard, then the programmer may reasonably rely on that, as
long as he doesn't claim or expect that his program will work properly
on a system that doesn't conform to POSIX. (Relying on POSIX
conformance is often perfectly reasonable, but it's not an assumption
we can make in this newsgroup, at least not without explicitly stating
it.)

--
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."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Mar 4 '07 #15

P: n/a
On Mar 4, 8:02 pm, Ben Pfaff <b...@cs.stanford.eduwrote:
"Bill Pursell" writes:
On Mar 4, 11:13 am, Flash Gordon wrote:
Bill Pursell wrote, On 04/03/07 06:57:
On Mar 3, 8:06 pm, Keith Thompson wrote:
It's likely to do so on most systems, but the standard doesn't
actually guarantee that a failing fopen() sets errno.
True. However, it strikes me that it is NOT the
programmer's responsibility to account for inadequacies
of the implementation.
Wrong IMHO. It is the programmer's responsibility to produce software
that works correctly on whatever system the customer wants even if the C
implementation on that system is completely useless.
So how do you deal with it? [...]

You can save a copy of errno and set errno to 0 before calling
fopen, then on fopen failure only print a message based on errno
if errno is nonzero.
I don't see that the standard guarantees that fopen will
not modify errno if it is succesful. Is there such a
guarantee? Or that fopen() won't fail and set errno
to a totally unrelated non-zero value, and give me:
foo: Invalid cross-device link

It seems to me that you have to rely on the implementation
for something, or you'll just go insane. I'll stick
with simply calling perror() (or err() or error()) but
I'm not going to reimburse Flash if his customer leaves. :)

--
Bill Pursell

Mar 4 '07 #16

P: n/a
On Mar 4, 8:52 pm, Keith Thompson <k...@mib.orgwrote:
"Bill Pursell" <bill.purs...@gmail.comwrites:
On Mar 3, 8:06 pm, Keith Thompson <k...@mib.orgwrote:
"Bill Pursell" <bill.purs...@gmail.comwrites:
On Mar 2, 5:52 am, "subramanian10...@yahoo.com, India"
<subramanian10...@yahoo.comwrote:
Consider the following program:
<some code snipped>
if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("Could not open input file :%s:\n", argv[1]);
exit(EXIT_FAILURE);
}
Just a note, you may be much happier replacing the printf line with:
perror(argv[1]);
It will print a much more meaningful message. eg:
[tmp]$ ./a.out foo
foo: No such file or directory
[tmp]$ touch foo; chmod 000 foo; ./a.out foo
foo: Permission denied
It's likely to do so on most systems, but the standard doesn't
actually guarantee that a failing fopen() sets errno.
True. However, it strikes me that it is NOT the
programmer's responsibility to account for inadequacies
of the implementation.

Yes, it is. Whose responsibility do you think it is?

A standard is a contract between the implementer and the programmer.
If an implementer claims his compiler conforms to the C standard, the
programmer may reasonably rely on that claim and make use of any
features guaranteed by the standard. If the programmer relies on
something *not* guaranteed by the standard (in this case, that fopen()
sets errno on failure), and the program misbehaves as a result, who is
responsible for the failure?
We're not talking about a failure here, we're talking about
the quality of an error message. On a good implementation,
perror() will generate a reasonable error message. On
a poor implementation, the error messsage will be less
helpful. Is it any more helpful to output:
"operation failed, and this implementation is so broken
that I can't tell you why." than it is to output a message
based on an incorrect value of errno? (well, yeah, I
guess it is...but not by much.)

I suppose I'll raise my standards and make a point
to only claim POSIX conformance for my code. Time
to remove -ansi from CFLAGS, I guess...

Mar 4 '07 #17

P: n/a
"Bill Pursell" <bi**********@gmail.comwrites:
On Mar 4, 8:02 pm, Ben Pfaff <b...@cs.stanford.eduwrote:
>"Bill Pursell" writes:
On Mar 4, 11:13 am, Flash Gordon wrote:
Bill Pursell wrote, On 04/03/07 06:57:
On Mar 3, 8:06 pm, Keith Thompson wrote:
It's likely to do so on most systems, but the standard doesn't
actually guarantee that a failing fopen() sets errno.
True. However, it strikes me that it is NOT the
programmer's responsibility to account for inadequacies
of the implementation.
>Wrong IMHO. It is the programmer's responsibility to produce software
that works correctly on whatever system the customer wants even if the C
implementation on that system is completely useless.
So how do you deal with it? [...]

You can save a copy of errno and set errno to 0 before calling
fopen, then on fopen failure only print a message based on errno
if errno is nonzero.

I don't see that the standard guarantees that fopen will
not modify errno if it is succesful. Is there such a
guarantee?
No. But: if fopen is successful, then you don't care what errno
is set to, or not set to.
Or that fopen() won't fail and set errno to a totally unrelated
non-zero value, and give me: foo: Invalid cross-device link
That's an issue that standard C gives you no way to avoid.
--
"You call this a *C* question? What the hell are you smoking?" --Kaz
Mar 4 '07 #18

P: n/a
"Bill Pursell" <bi**********@gmail.comwrites:
On Mar 4, 8:02 pm, Ben Pfaff <b...@cs.stanford.eduwrote:
>"Bill Pursell" writes:
On Mar 4, 11:13 am, Flash Gordon wrote:
Bill Pursell wrote, On 04/03/07 06:57:
On Mar 3, 8:06 pm, Keith Thompson wrote:
It's likely to do so on most systems, but the standard doesn't
actually guarantee that a failing fopen() sets errno.
True. However, it strikes me that it is NOT the
programmer's responsibility to account for inadequacies
of the implementation.
>Wrong IMHO. It is the programmer's responsibility to produce software
that works correctly on whatever system the customer wants even if the C
implementation on that system is completely useless.
So how do you deal with it? [...]

You can save a copy of errno and set errno to 0 before calling
fopen, then on fopen failure only print a message based on errno
if errno is nonzero.

I don't see that the standard guarantees that fopen will
not modify errno if it is succesful. Is there such a
guarantee? Or that fopen() won't fail and set errno
to a totally unrelated non-zero value, and give me:
foo: Invalid cross-device link
No, there is no such guarantee. In fact, setting errno to some
non-zero value on success is fairly likely, which is why you should
examine errno only after you know something has failed.

For example, suppose fopen() calls other lower-level functions
internally, and those other functions set errno if they fail:

FILE *fopen(/* blah blah */)
{
try_something();
/* fails, sets errno to EFOOBAR */
...
try_something_else();
/* that worked, leaves errno alone, fopen() succeeds */
return some_result;
}
It seems to me that you have to rely on the implementation
for something, or you'll just go insane. I'll stick
with simply calling perror() (or err() or error()) but
I'm not going to reimburse Flash if his customer leaves. :)
In this particular case, the worst you can expect is a meaningless
error message. But as I wrote in another response, what you're
probably doing here is depending on POSIX conformance, which is
perfectly ok as long as you're aware that that's what you're depending
on.

--
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."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Mar 4 '07 #19

P: n/a
>It's likely to do so on most systems, but the standard doesn't
>actually guarantee that a failing fopen() sets errno.
Since the standard doesn't guarantee that a failing fopen() does *NOT*
set errno, you should output it as part of an error message.
True. However, it strikes me that it is NOT the
programmer's responsibility to account for inadequacies
of the implementation.

Yes, it is. Whose responsibility do you think it is?

A standard is a contract between the implementer and the programmer.
If an implementer claims his compiler conforms to the C standard, the
programmer may reasonably rely on that claim and make use of any
features guaranteed by the standard. If the programmer relies on
something *not* guaranteed by the standard (in this case, that fopen()
sets errno on failure), and the program misbehaves as a result, who is
responsible for the failure?

We're not talking about a failure here, we're talking about
the quality of an error message. On a good implementation,
perror() will generate a reasonable error message. On
a poor implementation, the error messsage will be less
helpful. Is it any more helpful to output:
"operation failed, and this implementation is so broken
that I can't tell you why." than it is to output a message
based on an incorrect value of errno? (well, yeah, I
guess it is...but not by much.)
If it is known that fopen() will set errno to ENOMEM if it runs out
of memory, and ENOTTY (misleading at best) if opening the file
fails, then printing "operation failed: Not a typewriter" is an
improvement over a generic "operation failed and I don't have a
clue why", because in at least one circumstance (running out of
memory) it provides a better answer.

Mar 4 '07 #20

P: n/a
[regarding using strerror(errno) or equivalent to expand on
something like "fopen failed", despite the C Standard not
promising that fopen failure must set errno appropriately]

In article <11**********************@8g2000cwh.googlegroups.c om>
Bill Pursell <bi**********@gmail.comwrote:
>We're not talking about a failure here, we're talking about
the quality of an error message. On a good implementation,
perror() will generate a reasonable error message. On
a poor implementation, the error messsage will be less
helpful.
Indeed.

In the past, I have suggested -- and will continue to suggest --
that if you cannot depend on the implementation to go "above
and beyond" the Standard C requirements, you can do something
like this:

/* optional: errno = 0; */
fp = fopen(path, mode);
if (fp == NULL) {
fprintf(stderr, "unable to open %s; most recent system error was %s\n",
path, strerror(errno));
... do whatever else is appropriate here ...
}
>Is it any more helpful to output:
"operation failed, and this implementation is so broken
that I can't tell you why." than it is to output a message
based on an incorrect value of errno? (well, yeah, I
guess it is...but not by much.)
In this case, you might get (using a slightly different format):

prog: can't open foo.txt for reading;
most recent system error was "no such process"

on a "bad" system, and:

prog: can't open foo.txt for reading;
most recent system error was "too many open files"

on a "good" system. (And in fact, some pre-POSIX Unix-based systems
*would* fail to set errno if you had the maximum number of files
-- 20 -- open, so that the stdio routines in the C library ran out
of "FILE" objects and never made any system calls. If you were to
set errno to 0 before calling fopen(), strerror(errno) would be
"no error" or "success" or similar.)
>I suppose I'll raise my standards and make a point
to only claim POSIX conformance for my code. Time
to remove -ansi from CFLAGS, I guess...
In this particular case, I would have been happy to see the C
standards require fopen(), malloc(), and other such functions to
set errno on failure (ideally, C89 and C99 both, but any upgrade
along the way would have been welcome). But we must make do with
what we have. :-)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Mar 5 '07 #21

P: n/a
go***********@burditt.org (Gordon Burditt) writes:
>>It's likely to do so on most systems, but the standard doesn't
actually guarantee that a failing fopen() sets errno.
I wrote the above. Gordon, I do not give you permission to quote
anything I write here, either directly or indirectly, without
attributing it to me.
Since the standard doesn't guarantee that a failing fopen() does *NOT*
set errno, you should output it as part of an error message.
That's highly questionable.

[...]
If it is known that fopen() will set errno to ENOMEM if it runs out
of memory, and ENOTTY (misleading at best) if opening the file
fails, then printing "operation failed: Not a typewriter" is an
improvement over a generic "operation failed and I don't have a
clue why", because in at least one circumstance (running out of
memory) it provides a better answer.
And how is this known? If you happen to know what fopen() will set
errno to for certain failures, and that those errno values happen to
be meaningless in some cases, you can write system-specific code to
translate the error codes to something meaningful.

Whether a generic "open failed" is better or worse than a misleading
"open failed: Not a typewriter" depends on the audience, i.e., who's
going to be seeing the error message and acting on it.

--
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."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Mar 5 '07 #22

P: n/a
Bill Pursell wrote, On 04/03/07 19:45:
On Mar 4, 11:13 am, Flash Gordon <s...@flash-gordon.me.ukwrote:
>Bill Pursell wrote, On 04/03/07 06:57:
>>On Mar 3, 8:06 pm, Keith Thompson <k...@mib.orgwrote:
<snip>
>>>It's likely to do so on most systems, but the standard doesn't
actually guarantee that a failing fopen() sets errno.
True. However, it strikes me that it is NOT the
programmer's responsibility to account for inadequacies
of the implementation.
Wrong IMHO. It is the programmer's responsibility to produce software
that works correctly on whatever system the customer wants even if the C
implementation on that system is completely useless.

So how do you deal with it? Do you write a wrapper like the
following around every libc function that the standard doesn't
require to set errno? It seems rather kludgy.
<snip>

Actually we have one general purpose error handling function that checks
errno (and other error flags that either our code or other libraries
might have set) and reports errors appropriately. If we have got the
rest of the code write in terms of when errno and the other flags are
cleared (we are not perfect, but not doing too badly) then if greatly
increases the chance of a sensible error message.

Customers in my experience strongly dislike error messages that are
obviously garbage.
--
Flash Gordon
Mar 5 '07 #23

P: n/a
Bill Pursell wrote, On 04/03/07 21:03:
On Mar 4, 8:02 pm, Ben Pfaff <b...@cs.stanford.eduwrote:
>"Bill Pursell" writes:
>>On Mar 4, 11:13 am, Flash Gordon wrote:
Bill Pursell wrote, On 04/03/07 06:57:
On Mar 3, 8:06 pm, Keith Thompson wrote:
>It's likely to do so on most systems, but the standard doesn't
>actually guarantee that a failing fopen() sets errno.
True. However, it strikes me that it is NOT the
programmer's responsibility to account for inadequacies
of the implementation.
Wrong IMHO. It is the programmer's responsibility to produce software
that works correctly on whatever system the customer wants even if the C
implementation on that system is completely useless.
So how do you deal with it? [...]
You can save a copy of errno and set errno to 0 before calling
fopen, then on fopen failure only print a message based on errno
if errno is nonzero.

I don't see that the standard guarantees that fopen will
not modify errno if it is succesful. Is there such a
guarantee? Or that fopen() won't fail and set errno
to a totally unrelated non-zero value, and give me:
foo: Invalid cross-device link
Quite correct.
It seems to me that you have to rely on the implementation
for something, or you'll just go insane. I'll stick
with simply calling perror() (or err() or error()) but
I'm not going to reimburse Flash if his customer leaves. :)
I never said it has to be perfect (nothing ever is) or work on *every*
system, just that it is the programmers responsibility to get it working
on whatever systems the customer wants to use even if those systems are bad.

If all the systems you are interested in will do something sensible if
you just call perror (you won't get "File open failed because of
askdjnfaskjdbnfsdb") then you have done what is required. So if you will
accept I have to deal with systems that don't behave in what I consider
a sensible manner you don't have to reimburse me :-)
--
Flash Gordon
Mar 5 '07 #24

P: n/a
Bill Pursell wrote:
>
.... snip ...
>
I suppose I'll raise my standards and make a point
to only claim POSIX conformance for my code. Time
to remove -ansi from CFLAGS, I guess...
That's lowering your standards. The appropriate thing is to
isolate code that requires something that ISO does not guarantee,
and compile those modules alone with relaxed standards.

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
Mar 5 '07 #25

P: n/a
On Sun, 4 Mar 2007 20:38:27 -0500, CBFalconer wrote
(in article <45***************@yahoo.com>):
Bill Pursell wrote:
>>
... snip ...
>>
I suppose I'll raise my standards and make a point
to only claim POSIX conformance for my code. Time
to remove -ansi from CFLAGS, I guess...

That's lowering your standards.
Only if you have some made-up belief that one standard is better than
another. Otherwise you are just picking a different standard.
The appropriate thing is to
isolate code that requires something that ISO does not guarantee,
and compile those modules alone with relaxed standards.
That is an approach, but not the only one that is "appropriate", that
is dependent upon too many variables to claim generically.

--
Randy Howard (2reply remove FOOBAR)
"The power of accurate observation is called cynicism by those
who have not got it." - George Bernard Shaw

Mar 18 '07 #26

This discussion thread is closed

Replies have been disabled for this discussion.