meulenbr@cstw01.UUCP (Frans Meulenbroeks) (10/21/88)
Hi! I've encountered a number of problems using Minix/ST <stdio.h>. The major problem is that it defines NULL as 0. This is a killer on an ST since sizeof(char *) == 32 and sizeof(int) == 16. Solution: change the 0 in (char *)0 Some other problems are encountered when a program tries to access the private part of a FILE struct (e.g. the count field, which is normally called cnt), or when someone refers to _iob (which is _io_table on Minix). I have a quick and dirty fix using defines, which fixes most of these problems. The question is: should I post it (is there interest), and can I post it (context diffs will be greater than the complete file; however, I'm also a little reluctant to post the complete file without permission of Dr. Tanenbaum). A side note: don't expect that _doprintf uses the parameter order you're used to. It doesn't. Of course decent programs don't call _doprintf directly (but dirty ones like the curses lib do. -- Frans Meulenbroeks (meulenbr@cst.prl.philips.nl) Centre for Software Technology ( or try: ...!mcvax!philmds!prle!cst!meulenbr)
chris@mimsy.UUCP (Chris Torek) (10/22/88)
In article <249@cstw01.UUCP> meulenbr@cstw01.UUCP (Frans Meulenbroeks) writes: >I've encountered a number of problems using Minix/ST <stdio.h>. >The major problem is that it defines NULL as 0. >This is a killer on an ST since sizeof(char *) == 32 and sizeof(int) == 16. >Solution: change the 0 in (char *)0 Do NOT do this. In the absence of `void *' as a type, the only two correct and realistic ways to define NULL are `0' and `0L'. (If you read the draft ANSI C standard, you should see why I say this.) Instead, be sure to cast NULL whenever it is used as an argument to a function. >Some other problems are encountered when a program tries to access the >private part of a FILE struct . . . . Not surprising; you are not supposed to do this, but people will do all sorts of things.... >A side note: don't expect that _doprintf uses the parameter order you're >used to. It doesn't. Of course decent programs don't call _doprintf >directly (but dirty ones like the curses lib do. Curses should use vsprintf. vsprintf is like sprintf but gets a `va_list' argument, i.e., a pointer into the call stack, and vsprintf is basically a wrapper for the internal printf routine---sprintf is a bit more than a wrapper since it provides the call stack to which the va_list pointer will point. (Actually, curses should use a more general stdio, but this may be more than Minix needs as yet. Stdio currently calls read, write, lseek, and close on open FILEs. Rather than calling read, write, lseek, and close directly, it should call `a read routine', `a write routine', `a seek routine', and `a close routine'. Normally these would be the same ones, but another routine would `open' four functions rather than a file descriptor. Curses would then use this to `open' a curses window for writing, where the write function would put characters to the window. Then there are no magic buffer size limits like `no more than 127 characters printed at a time'. Note that the various routines must be given an argument so that, e.g., a curses window writer can tell to which window to print. My approach was to allow one pointer argument.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
dtynan@sultra.UUCP (Der Tynan) (10/25/88)
In article <249@cstw01.UUCP>, meulenbr@cstw01.UUCP (Frans Meulenbroeks) writes: > > This is a killer on an ST since sizeof(char *) == 32 and sizeof(int) == 16. > Solution: change the 0 in (char *)0 > > Frans Meulenbroeks (meulenbr@cst.prl.philips.nl) Hmmm. I've always been partial to the idea that sizeof(char *) == sizeof(int). In fact, I've seen a lot of code (not necessarily my own), which assumes this. If one needs sizeof(int) == 16, then use short. It's my belief that if you have a true 32-bit address space (lucky you), then there's no reason to keep ints to a small size. Of course, one should always use casts with NULL anyway. I don't know, offhand, of any compiler that requires this, but it's good practice, as shown by your problem. NULL is best left as 0, and for instance, if ((memptr = malloc(BUFSIZE)) == (char *)NULL) etc(); Hope this helps! - Der -- Reply: dtynan@sultra.UUCP (Der Tynan @ Tynan Computers) {mips,pyramid}!sultra!dtynan Cast a cold eye on life, on death. Horseman, pass by... [WBY]
FYS-EH%FINTUVM.BITNET@cunyvm.cuny.edu (Esa Heinonen) (10/27/88)
In article <249@cstw01.UUCP>, meulenbr@cstw01.UUCP (Frans Meulenbroeks) writes: > > This is a killer on an ST since sizeof(char *) == 32 and sizeof(int) == 16. > Solution: change the 0 in (char *)0 > (32*8)-bit pointers and (16*8)-bit ints, WOW :-) (just to be consistent with my signature) Finally, floats have become unnecessary (well, almost)... a 128-bit signed integer would have a range of -1.7E38 .. 1.7E38. Now all we need is a way to have fractions as well ?| You obviously meant "sizeof(char *) == 4 and sizeof(int) == 2" . ------------------------------------------------ | Esa Heinonen, University of Turku, Finland | ------------------------------------------------ | Bitnet: FYS-EH at FINTUVM | | Internet: FYS-EH at FINTUVM.UTU.FI | ------------------------------------------------ | "Minix? Just say WOW|" | ------------------------------------------------
siebren@cwi.nl (Siebren van der Zee) (10/27/88)
In article <249@cstw01.UUCP> meulenbr@cstw01.UUCP writes: >Hi! > >I've encountered a number of problems using Minix/ST <stdio.h>. >The major problem is that it defines NULL as 0. The major problem is that you forgot that Minix is modelled after V7 unix. >This is a killer on an ST since sizeof(char *) == 32 and sizeof(int) == 16. >Solution: change the 0 in (char *)0 It has been a killer ever since 32-bit architectures showed up, but that's not much of a problem: it kills braindamaged programmers. I consider this a nice side-effect. >Some other problems are encountered when a program tries to access the >private part of a FILE struct (e.g. the count field, which is normally >called cnt), or when someone refers to _iob (which is _io_table on >Minix). I have a quick and dirty fix using defines, which fixes most of ^^^^^ >these problems. The question is: should I post it (is there interest), No! Please!! Siebren van der Zee, CWI Amsterdanm "A kernel a day keeps the users away."
henry@utzoo.uucp (Henry Spencer) (10/29/88)
In article <2598@sultra.UUCP> dtynan@sultra.UUCP (Der Tynan) writes: >... I've always been partial to the idea that sizeof(char *) == sizeof(int). >In fact, I've seen a lot of code (not necessarily my own), which assumes this. Such code is broken. Unfortunately, there *is* a lot of it about. >If one needs sizeof(int) == 16, then use short. It's my belief that if you >have a true 32-bit address space (lucky you), then there's no reason to keep >ints to a small size... Can you say "performance"? Ints are supposed to be the "natural" width for the machine, which is often taken to mean the width that performs best. On the 16-bit 680x0s, there is a sticky decision to be made: 16-bit ints are considerably faster, 32-bit ints are more useful and cause less trouble with poorly-written software. Not an easy choice, and there is no unanimity among C compilers on it. >Of course, one should always use casts with NULL anyway. No, the only place where NULL must be cast is as a function parameter. But casting it *there* is very important. > if ((memptr = malloc(BUFSIZE)) == (char *)NULL) This is silly; any compiler that isn't totally brain-dead will do exactly the same thing with or without the cast. Problems arise only when the compiler cannot tell what the type is supposed to be, and function calls are the only place where that really crops up. (Note, a machine with 16-bit ints and 32-bit pointers has a related problem with return values: the calling function *must* know the correct type of the return value. Many programs are sloppy about this, since the default type -- int -- happens to work right for pointer-valued functions on VAXen and the like. Not so when sizeof(int) != sizeof(char*).) -- The dream *IS* alive... | Henry Spencer at U of Toronto Zoology but not at NASA. |uunet!attcan!utzoo!henry henry@zoo.toronto.edu
mem@zinn.MV.COM (Mark E. Mallett) (10/31/88)
In article <2598@sultra.UUCP> dtynan@sultra.UUCP (Der Tynan) writes: >Hmmm. I've always been partial to the idea that sizeof(char *) == sizeof(int). >In fact, I've seen a lot of code (not necessarily my own), which assumes this. >If one needs sizeof(int) == 16, then use short. It's my belief that if you >have a true 32-bit address space (lucky you), then there's no reason to keep >ints to a small size. Of course it doesn't matter what you're partial to your what you're beliefs are, what matters is the language definition and the compiler implementation. The only assumption you should make about an int is that it is a size that is optimally handled by your hardware, and sometimes that assumption is at the whim of the compiler writer. If you really need to make assumptions -- any assumptions -- about the size and class of your declarations and their modifiers, use typedefs and/or defines to devise your own metatypes, and use those metatypes where storage characteristics must match some predetermined criteria. > Of course, one should always use casts with NULL anyway. One should only have to use casts with NULL if NULL is improperly defined, and even then using the cast won't necessarily help you. -mm- -- Mark E. Mallett Zinn Computer Co/ PO Box 4188/ Manchester NH/ 03103 Bus. Phone: 603 645 5069 Home: 603 424 8129 uucp: mem@zinn.MV.COM ( ...{decvax|elrond|harvard}!zinn!mem ) BIX: mmallett
chris@mimsy.UUCP (Chris Torek) (10/31/88)
I suppose I had best post this again....
From: chris@mimsy.UUCP (Chris Torek)
Newsgroups: comp.lang.c
Subject: Re: NULL etc.
Message-ID: <12290@mimsy.UUCP>
Date: 2 Jul 88 20:36:44 GMT
References: <MWlAyzy00hIE82Q1Qc@cs.cmu.edu> <6966@cup.portal.com> <3458@rpp386.UUCP>
Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742
Lines: 91
C's untyped nil pointer, which MUST be given a type before it can be
used correctly, is written as `0' (and `0L', and possibly using
constant integer expressions, depending on whose language definition you use;
but `0' must work). After it has been given a type (`(char *)0') it
becomes a nil pointer of that type. Once it has a type (if we ignore
some fine points in the draft proposed American National Standard for
C, many of which are unlikely to be implemented in current C compilers)
it may not be used as a nil pointer of another type. Hence (char *)0
is a nil pointer to char, and as such may not be used as a nil pointer
to int, or a nil pointer to struct tcurts, or indeed as anything other
than a pointer to char. It may work---indeed, it is more likely to
work than to fail---but it is incorrect and unportable, and should (and
does in PCC) draw at least a warning from the compiler.
There are only two ways that the untyped nil pointer can acquire a
type, namely assignment and comparison. Casts are a special case of
assignment, as are arguments to functions that have prototypes in
scope. Where this causes the most trouble is in arguments to functions
that do not have prototypes in scope, or for which the prototype does
not specify a type for that argument: e.g., execl():
f() {
void execl(char *, ...);
execl("prog", "prog", "arg1", "arg2", ___);
}
The only correct way to fill in the blank is with (char *)0 (or
possibly (char *)0L and similar tricks; outside of obfuscated C
contests, these tricks are not worth considering). If NULL is
defined as 0 (or 0L or (void *)0), (char *)NULL is equivalent and
hence also correct.
The dpANS has at present one more instance of an `untyped' nil pointer,
namely `(void *)0'. This is an anomaly in the type system, and, while
it has some beneficial properties, I believe that overall it makes the
situation worse, not better. The differences between using `0' and
`(void *)0' as a `generic nil' are, first, that while 0 is also an
integer constant, (void *)0 is not, and second, that (void *)0 is also
a typed nil pointer (ouch!---more below).
Suppose that NULL is defined as either `0' or `(void *)0'---one of the
two untyped nil pointers---but that we do not know which one. Which of
the following calls are correct?
/* defintions before the fragments (note lack of prototypes) */
void f1(cp) char *cp; { <code> }
void f2(ip) int *ip; { <code> }
void f3(vp) void *vp; { <code> }
...
f1(NULL); /* call 1 */
f1((char *)NULL); /* call 2 */
f2(NULL); /* call 3 */
f2((int *)NULL); /* call 4 */
f3(NULL); /* call 5 */
f3((void *)NULL); /* call 6 */
It is easy to see that calls 2, 4, and 6 (which cast their arguments
and hence provide types) are correct. The surprise is that while calls
1, 3, and 5 are all wrong if NULL is defined as `0', calls 1 and 5 are
both correct, or at least will both work, if NULL is defined as
`(void *)0'. Call 3 is wrong in any case.
We can get away with `f1((void *)0)' only because of a technicality:
the dpANS says that (void *) and (char *) must have the same
representation (which more or less means `must be the same type'), and
because (void *) is a valid pointer type, (void *)0 must be a valid nil
pointer of type `void *', and thus must also be a valid nil pointer of
type `char *'. (Actually, this argument glosses over a subsidiary
technicality, in that there is no guarantee that there is only ONE
valid nil pointer of any given type, but that way lies madness. There
are more arguments about whether `same representation' implies
`indistinguishable'; these, too, are best left untouched.)
There are no ANSI-conformant C compilers, for there is as yet no ANSI C
standard. One should therefore assume that code may have to run under
a compiler where NULL is defined as `0', not as `(void *)0', and should
therefore avoid calls like 1, 3, and 5 above.
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
dal@midgard.UUCP (Dale Schumacher) (11/01/88)
In article <7683@boring.cwi.nl> siebren@cwi.nl (Siebren van der Zee) writes: |In article <249@cstw01.UUCP> meulenbr@cstw01.UUCP writes: |>Hi! |> |>I've encountered a number of problems using Minix/ST <stdio.h>. |>The major problem is that it defines NULL as 0. [...] |>This is a killer on an ST since sizeof(char *) == 32 and sizeof(int) == 16. |>Solution: change the 0 in (char *)0 | |It has been a killer ever since 32-bit architectures showed up The X3J11 C standard proposal discusses this problem. It states that NULL may be defined as 0, 0L or ((void *) 0) as needed by an implementation. Therefore, is makes sense for NULL to be 0 (maybe) on the PC version, and 0L on the ST. Other liberties, like assuming sizeof(int)==sizeof(char *) and failing to declare pointer return values, are simply NON-PORTABLE and should not be used in Minix-related code or anything else pretending to be portable. I think it is very desirable to have code which compiles under Minix-PC work properly under Minix-ST with NO CHANGES, and visa-versa. I don't think this is unreasonable to expect. P.S.: When we get a more ansi-conformal compiler for Minix, possibly from Sozobon, NULL would change to the ((void *) 0) that it SHOULD be.
randy@umn-cs.CS.UMN.EDU (Randy Orrison) (11/02/88)
In article <486@midgard.UUCP> dal@syntel.UUCP (Dale Schumacher) writes: |In article <7683@boring.cwi.nl> siebren@cwi.nl (Siebren van der Zee) writes: ||In article <249@cstw01.UUCP> meulenbr@cstw01.UUCP writes: ||>Hi! ||>I've encountered a number of problems using Minix/ST <stdio.h>. ||>The major problem is that it defines NULL as 0. THIS IS NOT A PROBLEM. ||>This is a killer on an ST since sizeof(char *) == 32 and sizeof(int) == 16. ||>Solution: change the 0 in (char *)0 SOLUTION: cast NULL in function calls |The X3J11 C standard proposal discusses this problem. It states that NULL |may be defined as 0, 0L or ((void *) 0) as needed by an implementation. |Therefore, is makes sense for NULL to be 0 (maybe) on the PC version, and |0L on the ST. If used properly, the definition of NULL is irrelevant. In the context of an assignment or comparison, the compiler can figure out the appropriate type and will do the cast for you. In the context of a parameter to a function, there is NO DEFINITION that will work universally, and so it MUST BE CAST to the appropriate type. (Exception: In ANSI C, function prototypes will allow the compiler to figure out the type and do the cast for you. (in which case the definition again doesn't matter.)) |Other liberties, like assuming sizeof(int)==sizeof(char *) |and failing to declare pointer return values, are simply NON-PORTABLE and |should not be used in Minix-related code or anything else pretending to be |portable. I think it is very desirable to have code which compiles under |Minix-PC work properly under Minix-ST with NO CHANGES, and visa-versa. I |don't think this is unreasonable to expect. Agreed, whole heartedly. |P.S.: When we get a more ansi-conformal compiler for Minix, possibly from |Sozobon, NULL would change to the ((void *) 0) that it SHOULD be. This really doesn't matter... Summary: For any definition of NULL, and any foo_type or mumble: foo_type *a; a = NULL; /* IS portable */ if (a == NULL) /* IS portable */ my_func (NULL); /* is NOT portable (unless there's a prototype) */ my_func ((mumble *)NULL); /* IS portable, and REQUIRED for portability under pre-ANSI C */ -- Randy Orrison, Chemical Computer Thinking Battery -- randy@cctb.mn.org (aka randy@{ux.acss.umn.edu, umn-cs.uucp, umnacca.bitnet, halcdc.uucp}) If you think last Tuesday was a drag, wait till you see what happens tomorrow!
kirkenda@psu-cs.UUCP (Steve Kirkendall) (11/03/88)
In article <397@zinn.MV.COM> mem@zinn.MV.COM (Mark E. Mallett) writes: >In article <2598@sultra.UUCP> dtynan@sultra.UUCP (Der Tynan) writes: >>Hmmm. I've always been partial to the idea that sizeof(char *) == sizeof(int). >>In fact, I've seen a lot of code (not necessarily my own), which assumes this. >>If one needs sizeof(int) == 16, then use short. It's my belief that if you >>have a true 32-bit address space (lucky you), then there's no reason to keep >>ints to a small size. > >Of course it doesn't matter what you're partial to your what you're >beliefs are, what matters is the language definition and the compiler >implementation. The only assumption you should make about an int is that >it is a size that is optimally handled by your hardware, and sometimes >that assumption is at the whim of the compiler writer Sure, *I* write good, portable code. Anybody who does a lot of MINIX coding will have to learn to be careful, and that ain't all bad. Unfortunately, there are some people in this world who don't... so some highly desirable programs are going to be tough to port to MINIX/ST. One painful example: GCC. The author (Stallman) allowed a lot pointer/int confusion to creep into his code, so now, to get gcc running under MINIX/ST somebody is going to have to dig through (I'm guessing here) about 70,000 lines of code. BTW, there's more to the issue of pointer/int confusion than just the size of the data objects. You also have to worry about the convention that the compiler uses for returning values from functions. For example, ints might be returned in D0 while pointers are returned in A0. If your code confuses pointers and integers, you are assuming not only that they are the same size, but also that they use the same register for returning values.
THELBEKK%NORUNIT.BITNET@cunyvm.cuny.edu (11/04/88)
With regard to portability problems: It was mentioned that some pointer versus int assumptions had "been allowed to creep into" GNU CC. This is nothing new to me... I've had occasion to work with several programs by Stallman & Co, and while admitting freely that RMS is something of a genius, and FSF just what the doctor ordered, it seems that the assumtion that (sizeof(int) == sizeof(int *) == 32
THELBEKK%NORUNIT.BITNET@cunyvm.cuny.edu (11/04/88)
With regard to portability problems: It was mentioned that some pointer versus int assumptions had "been allowed to creep into" GNU CC. This is nothing new to me... I've had occasion to work with several programs by Stallman & Co, and while admitting freely that RMS is something of a genius, and FSF just what the doctor ordered, it seems that the assumtion that (sizeof(int) == sizeof(int *) == 32) is pretty much accepted. In fact, parameters to functions and return values of functions are often explicitly declared as int. I ported GNU Bison to Microsoft C under DOS, and it was a pretty tough job. Must have rewritten pointer arithmetic in some 30 or 40 places from what it was to what it should have been, in addition to all the other little fixes necessary. It was worth it, the program now compiles with no warnings at max warning level, and works perfectly -- it has already generated compilers successfully under DOS. Anyway, beware of GNU software on 16-bit machines; it will usually need quite a bit of work to get it running... -tih
egisin@watmath.waterloo.edu (Eric Gisin) (11/05/88)
In article <1187@psu-cs.UUCP>, kirkenda@psu-cs.UUCP (Steve Kirkendall) writes:
< there are some people in this world who don't... so some highly desirable
< programs are going to be tough to port to MINIX/ST.
<
< One painful example: GCC. The author (Stallman) allowed a lot pointer/int
< confusion to creep into his code, so now, to get gcc running under MINIX/ST
< somebody is going to have to dig through (I'm guessing here) about 70,000
< lines of code.
No, just compile GCC and the libraries with 32-bit ints.
You will have to re-write the system call library to
convert between the application's 32-bit ints and the
kernel's 16-bit ints. That's how the ST port of GCC was done.
dtynan@sultra.UUCP (Der Tynan) (11/05/88)
In article <5181@louie.udel.EDU>, THELBEKK%NORUNIT.BITNET@cunyvm.cuny.edu writes: > With regard to portability problems: It was mentioned that some pointer > versus int assumptions had "been allowed to creep into" GNU CC. This is > nothing new to me... I've had occasion to work with several programs > by Stallman & Co, and while admitting freely that RMS is something of a > genius, and FSF just what the doctor ordered, it seems that the assumtion > that (sizeof(int) == sizeof(int *) == 32 Ok, for the benefit of those who may have missed earlier postings by me, on the subject of GNU, I'm enclosing a small section from the GNU Programming Standards Manual. Note that this is not trying to tell us how to program in C, but how to write code for the GNU project. Perhaps this will finally clear up the comments about FSF, and sixteen-bit machines... Portability standards: Much of what is called "portability" in the Unix world refers to porting to different Unix versions. This is not relevant to GNU software, because its purpose is to run on top of one and only one kernel, the GNU kernel, compiled with one and only one C compiler, the GNU C compiler. The amount and kinds of variation among GNU systems on different cpu's will be like the variation among Berkeley 4.3 systems on different cpu's. [Portions deleted for brevity] It remains necessary to worry about differences among cpu types, such as the difference in byte ordering and alignment restrictions. However, I don't expect 16-bit machines ever to be supported by GNU, so there is no point in spending any time to consider the possibility that an int will be less than 32 bits. You can assume that it is reasonable to use a meg of memory. Don't strain to reduce memory usage unless it can get to that level. If your program creates complicated data structures, just make them in core and give a fatal error if malloc returns zero. Reprinted without permission. I hope this dispells some of the myths about using GNU software on a PC. It *may* be possible now, but that doesn't mean that the *next* version will fit in a 64K segment. Of course, on the other hand, GNUUCP *will* work on a PC (probably an oversight :-), and I hope to surface a MINIX version soon... - Der -- dtynan@Tynan.COM (Dermot Tynan @ Tynan Computers) {apple,mips,pyramid,uunet}!zorba.Tynan.COM!dtynan --- God invented alcohol to keep the Irish from taking over the planet ---
bill@uhccux.uhcc.hawaii.edu (William J. King) (11/11/88)
anyone have Andy Tannenbaum's e-mail address?