[comp.unix.questions] write

dhesi@bsu-cs.UUCP (Rahul Dhesi) (07/23/87)

My System V Release 2 documentation as supplied with Microport System
V/AT says:

     int write (fildes, buf, nbytes)
     int fildes;
     char *buf;
     unsigned nbytes;

This is incorrect:  since write() normally returns the number of bytes
written, its return value should be of the same type as nbytes; but
since it can return -1, its return value must be signed.  Hence nbytes
should not be unsigned.  In "Advanced UNIX Programming", Marc J.
Rochkind describes the write() system call with the same inconsistent
parameter declarations.

The real problem is that if I declare and use write() correctly, lint
complains, because the lint library wants nbytes to be unsigned.  And I
don't WANT to declare it incorrectly.
-- 
Rahul Dhesi         UUCP:  {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi

gwyn@brl-smoke.ARPA (Doug Gwyn ) (07/24/87)

In article <868@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
>     int write (fildes, buf, nbytes)
>     int fildes;
>     char *buf;
>     unsigned nbytes;
>This is incorrect...

NO, it's correct.  What is unfortunate is that this is one of those functions
that was designed to return an error indicator "in band", so it usurped one
of the useful values from what should have been the range of return values.
This means in some implementations one has to test errno as well as the
return value, in the case that nbytes is indistinguishable from -1 when
coerced to an (int).  Usually you would only see that on a 16-bit machine
that supports 65535-byte DMA, when you request 65535 bytes.  That is a most
unlikely situation.  Somewhat more likely is the case that nbytes on a 16-bit
machine might be too large to be expressed as an (int), so one's code would
have to take that into account.

Note that the value type of the sizeof operator is unsigned, so unsigned
nbytes is a "natural" (one would never be writing a negative number of bytes).

Keep in mind that when the basic UNIX system interfaces were designed, types
were all slopped together with abandon.  It was only later that people began
to try to straighten out the type confusion, but because they were constrained
by the operation of existing systems there was only so much that they could do.

peter@citcom.UUCP (Peter Klosky) (07/24/87)

A number of unix applications developed with a disregard for
the two-byte integer machines can cause all sorts of bugs,
and the syntax of arguments to write sort of scratches the bites.
In specific, certain applications will read small files
such as keyboard macros or news articles by using stat to
find the file size, mallocing space for the file, then reading
in the whole thing at once.  The problem is when the keyboard
macros or news articles grow beyond the limit, the applications
sort of get lost and run off the road.  As another writer has
already pointed out, more thought could have gone into the original
design of the write arguments.

This type of problem is made worse by technical leaders who do
not understand the difference between an int and a long, and in
general have a problem with fixing a program that gives no
trouble on the existing hardware.  In specific, I can recall an
incident where a juniour programmer was running lint on a 
four-byte machine and found an O.S. include file with the type
of a time set to an int as opposed to a long.  He suggested the
type of a time value be changed to a long in the system include file;
the technical leader who was responsible for the include files
said something like "Why don't you leave me alone so we can cut
yet another release of this OS.  Just recompile your program and
everything will be fine."  Whatever the new guy complained about,
the technical leader would always tell him to recompile, then
everything would be "clean."  To make a long story short, the
technical leader lasted less than a few months at his position,
largely because he had a poor understanding of details.
-- 
Peter Klosky, Citcom Systems (materiel de telecommunications)
seismo!vrdxhq!baskin!citcom!peter (703) 689-2800 x 235

mikep@ism780c.UUCP (Michael A. Petonic) (07/24/87)

In article <868@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
}My System V Release 2 documentation as supplied with Microport System
}V/AT says:
}
}     int write (fildes, buf, nbytes)
}     int fildes;
}     char *buf;
}     unsigned nbytes;
}
}This is incorrect:  since write() normally returns the number of bytes
}written, its return value should be of the same type as nbytes; but
}since it can return -1, its return value must be signed.  Hence nbytes
}should not be unsigned.  In "Advanced UNIX Programming", Marc J.
}Rochkind describes the write() system call with the same inconsistent
}parameter declarations.
}
}The real problem is that if I declare and use write() correctly, lint
}complains, because the lint library wants nbytes to be unsigned.  And I
}don't WANT to declare it incorrectly.
}-- 
}Rahul Dhesi         UUCP:  {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi


According to the SVID (System V Interface Definition), AT&T differs
from the /usr/group proposal by having nbytes be of type size_t 
(typedef'd in an included file) which is an integer.

I think the SVID also mentioned that size_t was going to be changed
into an unsigned, but I don't know when or in what release.
-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
The company and all my associates and friends and ESPECIALLY the 
government put me up to say all this useless trash.
MikeP    {seismo|sdcrdcf}!ism780c!mikep "Some of my best friends are Bigots..."

dhesi@bsu-cs.UUCP (Rahul Dhesi) (07/28/87)

In article <868@bsu-cs.UUCP> I said that in the declaration for 
"write (fildes, buf, nbytes)", nbytes should be int because write()
returns an int value.  Several people disagreed, one or two quite
strongly.

I looked around in a few places to see what others have written.  
Everybody seems to agree that write() returns an int value. But:

      nbytes is unsigned              nbytes is int
      ------ -- --------              ------ -- ---
System V Release 2 manual             4.2BSD and 4.3BSD manual
entry for write()                     entry for write()

Description of write() by Marc        Description of write() by Maurice
J. Rochkind in "Advanced UNIX         J. Bach in "The Design of the
Programming", p 28.                   UNIX Operating System", p 453.

Microsoft C 3.0 manual entry          Borland's Turbo C 1.0 manual
for write()                           entry for write()

I suspect that the left column represents the way things have been,
and the right column represents the way some people feel things 
ought to be.

Also, I looked at "Reliable Data Structures in C" by Thomas Plum.
He is mostly discussing draft ANSI C, and that does not define write().
He shows how to implement an equivalent function bin_write() portably.
And he uses a signed variable for nbytes.

But on a machine with 16-bit ints, using a signed nbytes unnecessarily
restricts the size of the largest block that can be written.

One possible solution:

     size_t write (fildes, buf, nbytes)
     int fildes; char *buf; size_t nbytes;

     The value supplied for `nbytes' must be in the range
     0 through (((size_t) -1) - 1), where size_t is an unsigned type
     defined in a header file.  Up to `nbytes' bytes of data are
     written each time write() is called.  The return value is the
     actual number of bytes written, unless an error occurs, in which
     case the value returned is ((size_t) -1).
-- 
Rahul Dhesi         UUCP:  {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi

decot@hpisod2.HP.COM (Dave Decot) (07/29/87)

> One possible solution:
> 
>      size_t write (fildes, buf, nbytes)
>      int fildes; char *buf; size_t nbytes;
> 
>      The value supplied for `nbytes' must be in the range
>      0 through (((size_t) -1) - 1), where size_t is an unsigned type
>      defined in a header file.  Up to `nbytes' bytes of data are
>      written each time write() is called.  The return value is the
>      actual number of bytes written, unless an error occurs, in which
>      case the value returned is ((size_t) -1).

This assumes a two's complement representation of integers.

Dave Decot
hpda!decot

ka@hropus.UUCP (Kenneth Almquist) (07/31/87)

> I suspect that the left column [with nbytes unsigned] represents the
> way things have been, and the right column [with nbytes signed] represents
> the way some people feel things ought to be.

Originally, nbytes was signed.  The write system call predates the
invention of the unsigned data type.
					Kenneth Almquist