[comp.unix.wizards] Manual may mislead many mighty men.

rr@csuna.cs.uh.edu (Ravi Ramachandran) (03/17/90)

First, apologies if this subject has been thrashed to death before.
Now, let the mystery story unfold.


I remember that when I first tried fooling around with semaphores, I
had a little trouble. Then I pulled out the stuff from a nice book: 
"UNIX System V  Prog. Guide" (AT&T) - Prentice hall.

A pal of mine was trying to use semaphores on a Sys V Rel 3 system,
yesterday, and was having trouble with the semop() command.

To quote from the manual,
int semop(semid, sops, nsops)
int semid;
struct sembuf **sops;
int nsops;


while my program had,

struct sembuf sops[10];
   rtrn = semop(semid, sops, nsops);

Throw your concentration on the second field. As you can see, they are
different. (Modified his program & it worked.)  However, we couldn't
believe that the manual could be wrong. Decided to refer to the books
by the gurus.


Looked up "Adv. Unix Prog." (Marc J. Rochkind) - Prentice Hall.

On pg 188, he says (prob. from the manual):
int semop(sid, ops, nops)
int sid;
struct sembuf (*ops)[];
int nops;

However, the program on pg. 190  goes:
  struct sembuf sb;
  semop(semid, &sb, 1);


Finally, checked up "The Design of the UNIX operating system"  (Maurice
J. Bach)  - Prentice-Hall.
On pg. 373 he says, "...oplist is a pointer to an array of semaphore
operations ..." 
(It should be " oplist is an array of ..." ?)

The prog. in Fig 11.14 gives:
struct sembuf  psembuf, vsembuf;
semop(semid, &psembuf, 1);
semop(semid, &vsembuf, 1);


As a last measure, ran my version of semaphores on a Tolerant, Pyramid,
and an OST. Works. Checked the man pages on all these systems. They
are the ones with the double pointer. So, what's the deal? I know there
must be zillions of people who have noticed this before.


The butler did it,
  --ravi-


PS: Just check the SUN man pages; seems to be the right way: 
int semop(semid, sops, nsops)
int semid;
struct sembuf *sops;
int nsops;

PPS: The only reason that I've mentioned a couple of books here is b'cos
those books have been my UNIX bibles.

gwyn@smoke.BRL.MIL (Doug Gwyn) (03/18/90)

In article <24407@uhnix1.uh.edu> rr@cs.uh.edu (Ravi Ramachandran) writes:
>On pg. 373 he says, "...oplist is a pointer to an array of semaphore
>operations ..." 
>(It should be " oplist is an array of ..." ?)

I think this confusion occurred because of the way that C arrays have
traditionally been botched.  The correct type for the second argument
to semop() is (struct sembuf *), and it is expected to point to THE
FIRST ELEMENT OF a user-defined array of semaphore operation structures.
Because of the C array botch, most documentation (e.g. SVID3) has been
calling this a "pointer to a user-defined array of ...".  In pre-ANSI C
implementations, it was not usually possible to construct a pointer to
an array; an attempt to do so would be coerced by the compiler into a
pointer to the array's first element.  In ANSI C the distinction is
important, and the words "the first element of" should be added to the
documentation.

Note that your suggested fix is wrong; a function parameter cannot have
array type in either old or new C.

decot@hpisod2.HP.COM (Dave Decot) (03/19/90)

> A pal of mine was trying to use semaphores on a Sys V Rel 3 system,
> yesterday, and was having trouble with the semop() command.
> 
> To quote from the manual,
> int semop(semid, sops, nsops)
> int semid;
> struct sembuf **sops;
> int nsops;

The above is incorrect, and probably based on a misunderstanding of some
bad documentation (probably the bad documentation is on the same page).

> while my program had,
> 
> struct sembuf sops[10];
>    rtrn = semop(semid, sops, nsops);

The above is completely correct.

> Looked up "Adv. Unix Prog." (Marc J. Rochkind) - Prentice Hall.
> 
> On pg 188, he says (prob. from the manual):
> int semop(sid, ops, nops)
> int sid;
> struct sembuf (*ops)[];
> int nops;

The above is wrong, and is probably based on a misunderstanding of
the misused phrase "a pointer to an array" (see below).

> However, the program on pg. 190  goes:
>   struct sembuf sb;
>   semop(semid, &sb, 1);

The above works, because you are using an "array" of size 1, and the
"name" of your "array" is &sb.  This would also work:

struct sembuf sb[1];
semop(semid, sb, 1);

> 
> Finally, checked up "The Design of the UNIX operating system"  (Maurice
> J. Bach)  - Prentice-Hall.
> On pg. 373 he says, "...oplist is a pointer to an array of semaphore
> operations ..." 
> (It should be " oplist is an array of ..." ?)

No, it *should* be "oplist is a pointer to the first element of an array of
semaphore operations" if oplist is the name of the second argument
to semop().  Remember that it's impossible to pass arrays to functions.
The phrase "pointer to an array of" is often misused when "pointer to
the first element of an array of" is meant, even in classic holy
scriptures.  The reason "everyone understands it" is because types of
the form "pointer to an array of" are much less often used.

Here's a "pointer to an array of 10 characters":

  int (*p)[10];

As a parameter declaration, here's a "pointer to the first element of
an array of 10 characters":

  int p[10];

However, most compilers ignore the 10 since it is irrelevant.  In fact,
I'm not even sure sizeof(p) even cares about the 10.

> The prog. in Fig 11.14 gives:
> struct sembuf  psembuf, vsembuf;
> semop(semid, &psembuf, 1);
> semop(semid, &vsembuf, 1);

These are correct, because you are using semaphore sets of size 1.
A pointer to a variable of a certain type works just as fine as
a pointer to the first element of an array containing one element
of that type.

> PS: Just check the SUN man pages; seems to be the right way: 
> int semop(semid, sops, nsops)
> int semid;
> struct sembuf *sops;
> int nsops;

That is a correct declaration.  HP-UX has it correct as well.

Dave Decot