No fread and fwrite for wide characters?

L

Lauri Alanko

It seems that the standard I/O operations for wide characters are
conspicuously lacking functions that read or write an array of
arbitrary wide characters into a stream. E.g. for writing, there's
only fputws, which writes a L'\0'-terminated string, not including the
terminator. So if there's a buffer that may contain L'\0', one has to
iterate it using fputwc, maybe with the assistance of fputws if an
exact count of successfully written characters is not needed.

The workaround is not a big deal, but this seems like a strange
omission, since otherwise there are wide I/O counterparts for all
basic byte I/O operations. Granted, mixing text and null characters is
not very common, but it does happen, e.g. when null characters are
used as field separators.

So does anyone have an idea why "fwwrite" and "fwread" are missing?

Thanks,


Lauri
 
J

James Kuyper

It seems that the standard I/O operations for wide characters are
conspicuously lacking functions that read or write an array of
arbitrary wide characters into a stream. E.g. for writing, there's
only fputws, which writes a L'\0'-terminated string, not including the
terminator. So if there's a buffer that may contain L'\0', one has to
iterate it using fputwc, maybe with the assistance of fputws if an
exact count of successfully written characters is not needed.

The workaround is not a big deal, but this seems like a strange
omission, since otherwise there are wide I/O counterparts for all
basic byte I/O operations. Granted, mixing text and null characters is
not very common, but it does happen, e.g. when null characters are
used as field separators.

So does anyone have an idea why "fwwrite" and "fwread" are missing?

I'm not sure exactly what behavior you want fwwrite() to have. Here's
how the standard describes fwrite():
7.19.8.2 The fwrite function
Synopsis
#include <stdio.h>
size_t fwrite(const void * restrict ptr,
size_t size, size_t nmemb,
FILE * restrict stream);

Description
The fwrite function writes, from the array pointed to by ptr, up to nmemb elements
whose size is specified by size, to the stream pointed to by stream. For each object,
size calls are made to the fputc function, taking the values (in order) from an array of
unsigned char exactly overlaying the object. The file position indicator for the
stream (if defined) is advanced by the number of characters successfully written. If an
error occurs, the resulting value of the file position indicator for the stream is
indeterminate.

Returns
The fwrite function returns the number of elements successfully written, which will be
less than nmemb only if a write error is encountered. If size or nmemb is zero,
fwrite returns zero and the state of the stream remains unchanged.

Could you modify that description so that it describes what you want for
fwwrite()?
 
L

Lauri Alanko

Could you modify that description so that it describes what you want for
fwwrite()?

Not really, since the "element" concept of fwrite is not applicable to
wide characters (and even in general it's mostly a useless historical
remnant). But I'll do better, and provide a reference implementation:

size_t fwwrite(FILE* file, const wchar_t* wcs, size_t size)
{
for (size_t n = 0; n < size; n++) {
if (fputwc(wcs[n], file) == WEOF) {
return n;
}
}
return size;
}

Not a big deal to write by hand, sure, but the library implementation
could in all likelyhood do the same job more efficiently.


Lauri
 
J

James Kuyper

Not really, since the "element" concept of fwrite is not applicable to
wide characters (and even in general it's mostly a useless historical
remnant).

In most of my fwrite() calls, either the element size is 1 or the number
of elements is one; but for about 10% of my fwrite() calls, the
"element" concept is alive and well.
... But I'll do better, and provide a reference implementation:

size_t fwwrite(FILE* file, const wchar_t* wcs, size_t size)
{
for (size_t n = 0; n < size; n++) {
if (fputwc(wcs[n], file) == WEOF) {
return n;
}
}
return size;
}

So, this is not at all the wide character equivalent of fwrite(), which
makes more sense, since narrow characters have nothing to do fwrite().
So this really deserves some other name, one which doesn't imply a
non-existent parallel to fwrite().

Which narrow-character function did you consider this to be closest to?
It's similar to fputs(), except for the count, but there's already an
fputws(), which is an exact parallel to fputs().
 
L

Lauri Alanko

So, this is not at all the wide character equivalent of fwrite(), which
makes more sense, since narrow characters have nothing to do fwrite().

They certainly do, since as you quoted, fwrite is just a utility for
looping fputc()-calls. "Narrow characters" are bytes, after all.
Which narrow-character function did you consider this to be closest to?
It's similar to fputs(), except for the count, but there's already an
fputws(), which is an exact parallel to fputs().

The problem with fputws is that it cannot be used to output anything
that contains a null wide character. For narrow characters (bytes),
fputs has a similar problem, and that's where fwrite comes handy. So,
again, I'm looking for the X that solves fputs : fwrite :: fputws : X.


Lauri
 
H

Harald van Dijk

The problem with fputws is that it cannot be used to output anything
that contains a null wide character. For narrow characters (bytes),
fputs has a similar problem, and that's where fwrite comes handy.

Are you trying to write to a text stream or a binary stream? Null
characters are only portably useful for binary streams, but binary
wide-oriented streams are something that, while valid, I've never seen
a real use for before.
 
P

Phil Carmody

Lauri Alanko said:
They certainly do, since as you quoted, fwrite is just a utility for
looping fputc()-calls.

What are you gibbering about?

size_t fwrite(const void * restrict ptr,
size_t size, size_t nmemb,
FILE * restrict stream);

There is precisely *nothing* related to the characters one sends to fputc
in that function declaration. End of. Any attempts to counter my argument
are, like *ptr, void.

Phil
 
I

Ike Naar

What are you gibbering about?

size_t fwrite(const void * restrict ptr,
size_t size, size_t nmemb,
FILE * restrict stream);

There is precisely *nothing* related to the characters one sends to fputc
in that function declaration. End of. Any attempts to counter my argument
are, like *ptr, void.

7.19.3 p12:
The byte output functions write characters to the stream as if
by successive calls to the fputc function.

fwrite is one of the byte output functions (7.19.1 p5).
 
J

James Kuyper

What are you gibbering about?

size_t fwrite(const void * restrict ptr,
size_t size, size_t nmemb,
FILE * restrict stream);

There is precisely *nothing* related to the characters one sends to fputc
in that function declaration. End of. Any attempts to counter my argument
are, like *ptr, void.

As I cited earlier in this thread, 7.19.8.2p2 says: "For each object,
size calls are made to the fputc function, taking the values (in order)
from an array of unsigned char exactly overlaying the object."

That sounds a lot like looping over calls to fputc() to me. If you
interpreted "looping fputc() - calls" to mean anything inconsistent with
what 7.19.8.2p2 says, then you've probably misunderstood his intent.

I think that defining his proposed fwwrite() function by the analogy of
fputc():fwrite() :: fputwc():fwwrite() is faulty, but not by reason of
there being no relationship between fputc() and fwrite(). I've failed to
come up with a convincing explanation of what I find objectionable about
it, which is why I've not responded to that message.
 
L

Lauri Alanko

Are you trying to write to a text stream or a binary stream? Null
characters are only portably useful for binary streams, but binary
wide-oriented streams are something that, while valid, I've never seen
a real use for before.

I don't have an immediate application in mind. I'm writing a
general-purpose library and want to make sure that there are no
corner-cases, so I have to take into consideration even binary
wide-oriented streams, rare as they may be.

But as I mentioned, null characters are commonly used as field
separators, e.g. by "xargs -0" in unix, in order to allow spaces and
newlines within field contents. It's quite conceivable that one might
wish to produce wide characters within these fields, e.g. strings of a
foreign language that xargs would then pass to grep.


Lauri
 
P

Phil Carmody

Ike Naar said:
7.19.3 p12:
The byte output functions write characters to the stream as if
by successive calls to the fputc function.

fwrite is one of the byte output functions (7.19.1 p5).

You're right, and I retract and apologise. In this case, I believe I've
probably misinterpreted something said way earlier in the thread which
the above would also contradict, and which when I saw going unchallenged
I took as true. Maybe I'm misingerpreting the *whole thread*, as that p12
seems to be the immediate answer to everything. Thanks for hunting it
out and so succinctly correcting my unacceptable error.

Phil
 

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,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top