Tim_CDC_Roberts@cup.portal.com (03/18/89)
In <960@Portia.Stanford.EDU>, joe@hanauma (Joe Dellinger) asks: > What would you expect the following program to print out? > > > #include <stdio.h> > main() > { > char string[10]; > string[0] = '*'; > string[1] = '\0'; > printf("%s\n", string[1]); > } > > Just "\n", right? On our system it prints out "(null)\n"!!! No, I expect it to print out (null)\n. The '%s' format item expects to find a pointer_to_char on the stack. By specifying string[1], you have passed a _char_. This _char_ happens to have the value 0. When printf goes to use this as a pointer, it finds that it is a null pointer. To do what you expected, replace the printf with: printf("%s\n", &string[1]); ^ Trivia question: is the '(null)' output of printf standard or widespread? I know that Microsoft C does this; do other compilers? Tim_CDC_Roberts@cup.portal.com | Control Data... ...!sun!portal!cup.portal.com!tim_cdc_roberts | ...or it will control you.
ark@alice.UUCP (Andrew Koenig) (03/18/89)
In article <960@Portia.Stanford.EDU>, joe@hanauma (Joe Dellinger) writes: > What would you expect the following program to print out? > #include <stdio.h> > main() > { > char string[10]; > string[0] = '*'; > string[1] = '\0'; > printf("%s\n", string[1]); > } The program is invalid; the implementation is allowed to do as it pleases. You said string[1] = '\0'; which is equivalent to string[1] = 0; and then said printf("%s\n", string[1]); which is, of course, equivalent to printf("%s\n", 0); This asks printf to print characters starting at memory location 0; not quite what you probably wanted. Try this: printf("%s\n", &string[1]); or, equivalently, this: printf("%s\n", string+1); -- --Andrew Koenig ark@europa.att.com
bph@buengc.BU.EDU (Blair P. Houghton) (03/19/89)
In article <15938@cup.portal.com> Tim_CDC_Roberts@cup.portal.com writes: >In <960@Portia.Stanford.EDU>, joe@hanauma (Joe Dellinger) asks: > >> string[0] = '*'; >> string[1] = '\0'; >> printf("%s\n", string[1]); > >No, I expect it to print out (null)\n. The '%s' format item expects to > >Trivia question: is the '(null)' output of printf standard or widespread? >I know that Microsoft C does this; do other compilers? The uVAX/Ultrix C compiler ignores it whole. The only thing the program emits is the \n. (I checked it by "funkyprint | od -bc". One char out. \012. More interesting than I expected. Smells broken.) The Encore/Umax C compiler emits \022 \012. So, like, what's \022? My ASCII table says it's a "dc2". --Blair "Gesundheit."
gwyn@smoke.BRL.MIL (Doug Gwyn ) (03/19/89)
In article <2343@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes: >In article <15938@cup.portal.com> Tim_CDC_Roberts@cup.portal.com writes: >>Trivia question: is the '(null)' output of printf standard or widespread? AT&T UNIX System V Release 2.0 just printed out whatever was accidentally pointed at. In my version (BRL UNIX System V emulation for 4BSD), I decided that the test for a null pointer was cheap insurance and I also have *printf("%s",(char*)0) print "(null)" rather than behave randomly. Such matters concern what X3J11 dubbed "quality of implementation" issues.
barmar@think.COM (Barry Margolin) (03/20/89)
In article <2343@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes: >>In <960@Portia.Stanford.EDU>, joe@hanauma (Joe Dellinger) asks: >>> string[0] = '*'; >>> string[1] = '\0'; >>> printf("%s\n", string[1]); >The Encore/Umax C compiler emits \022 \012. So, like, what's \022? My >ASCII table says it's a "dc2". In this case, the fact that it's DC2 is immaterial. You passed a pointer to location 0 to printf, so it printed the string that happened to be at location 0 in memory, which appears to be \022<Space>. Barry Margolin Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar
joe@hanauma.stanford.edu (Joe Dellinger) (03/20/89)
Ooops. I realized my mistake about 1 minute after I posted, but it seems our news server is hyperactive and had already spread my errant article far and wide by then.... My posting DOES raise an important question, though, which I believe hasn't been addressed in any of the responses. I ran my program through lint with no complaint. Why doesn't "lint" catch this sort of error? And yes, I know, lint can't be expected to know the internal details of weird varargs programs... BUT, printf is hardly "weird". It gets used ALL the time. Why did the creators of lint not tackle error checking for all the varargs programs in the standard libraries? Will "ANSI Lint" solve this problem? If no, why not? It seems there is no better reason than laziness... \ /\ /\ /\/\/\/\/\/\/\.-.-.-.-.......___________ \ / \ / \ /Dept of Geophysics, Stanford University \/\/\.-.-....___ \/ \/ \/Joe Dellinger joe@hanauma.stanford.edu apple!hanauma!joe\/\.-._
chris@mimsy.UUCP (Chris Torek) (03/21/89)
In article <1013@Portia.Stanford.EDU> joe@hanauma.stanford.edu (Joe Dellinger) writes: >I ran my [printf] program through lint with no complaint. Why doesn't >"lint" catch this sort of error? And yes, I know, lint can't be expected >to know the internal details of weird varargs programs... > > BUT, printf is hardly "weird". It gets used ALL the time. >Why did the creators of lint not tackle error checking for all the >varargs programs in the standard libraries? Because it was hard. >Will "ANSI Lint" solve this problem? If no, why not? It seems there >is no better reason than laziness... Or disinterest. Here is what the 4.3BSD-tahoe lint has to say: % cat foo.c main() { char foo[10]; printf("%s\n", foo[1]); } % lint -h foo.c foo.c(1): warning: printf: (char *) format, (char) arg (arg 2) The change is due to Arthur Olson (elsie!ado). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
throopw@agarn.dg.com (Wayne A. Throop) (03/21/89)
> gwyn@smoke.BRL.MIL (Doug Gwyn ) > In my version (BRL UNIX System V emulation for 4BSD), I > decided that the test for a null pointer was cheap insurance and I also > have *printf("%s",(char*)0) print "(null)" rather than behave randomly. > Such matters concern what X3J11 dubbed "quality of implementation" issues. Uh... yeah. They involve some taste issues also, so let me add a tangential point. I'd personally prefer not to overload an "in-band" behavior to mean that something "out-of-band" happened. The check for the null pointer is cheap enough, I agree, but I'd druther not simply print a string in that case... it's practically a liscense to write non-portable code. I'd druther do something close to kill( getpid(), SIGSEGV ); in such a case. -- "Who would be fighting with the weather like this?" "Only a lunatic." "So you think D'Artagnian is involved?" --- Porthos, Athos, and Aramis. -- Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw
john@frog.UUCP (John Woods) (03/21/89)
In article <2343@buengc.BU.EDU>, bph@buengc.BU.EDU (Blair P. Houghton) writes: > In article <15938@cup.portal.com> Tim_CDC_Roberts@cup.portal.com writes: > >In <960@Portia.Stanford.EDU>, joe@hanauma (Joe Dellinger) asks: > >> string[0] = '*'; > >> string[1] = '\0'; > >> printf("%s\n", string[1]); > >Trivia question: is the '(null)' output of printf standard or widespread? > The uVAX/Ultrix C compiler ignores it whole. The only thing the program emits > is the \n. (I checked it by "funkyprint | od -bc". One char out. \012. > More interesting than I expected. Smells broken.) > The Encore/Umax C compiler emits \022 \012. So, like, what's \022? My > ASCII table says it's a "dc2". I'd bet dollars to holes in doughnuts that Ultrix's library (note: not the compiler) behaves that way because there are four zero-bytes at address 0. The first of them looks like an empty string (""). Or maybe they check for NULL and call it an empty string. The program running on the Encore probably sees \022\040\000 at address 0. A string with two characters, \022 and space. Note that there are some systems that could potentially bus-error instead of printing anything. To quote Henry's Ten Commandments, "2. Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end." (a wonderful set of dicta for printing in Fraktur and posting on one's wall :-) UNOS' printf routine displays a NULL %s value as <NULL POINTER>, a bit more verbose than (null) but equally useful. -- John Woods, Charles River Data Systems, Framingham MA, (508) 626-1101 ...!decvax!frog!john, john@frog.UUCP, ...!mit-eddie!jfw, jfw@eddie.mit.edu "He should be put in stocks in Lafeyette Square across from the White House and pelted with dead cats." - George F. Will
henry@utzoo.uucp (Henry Spencer) (03/22/89)
In article <1013@Portia.Stanford.EDU> joe@hanauma.stanford.edu (Joe Dellinger) writes: > ... printf is hardly "weird". It gets used ALL the time. >... Will "ANSI Lint" solve this problem? ... Ask your compiler supplier. ANSI C does not address details of the implementation, such as what error messages are emitted by what program. -- Welcome to Mars! Your | Henry Spencer at U of Toronto Zoology passport and visa, comrade? | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
jym@wheaties.ai.mit.edu (Jym Dyer) (03/22/89)
DEC's VAX C compiler (for VMS) crashes if you pass it a NULL for a string: printf("%s\n",NULL); Alas, it also crashes on this: printf("%.*s\n",0,NULL); Caveat emptor. <_Jym_>
gwyn@smoke.BRL.MIL (Doug Gwyn ) (03/22/89)
In article <4273@xyzzy.UUCP> throopw@agarn.dg.com (Wayne A. Throop) writes: >I'd druther do something close to > kill( getpid(), SIGSEGV ); >in such a case. I've had another similar suggestion mailed to me. All I can say is, my experience with this has been that printing "(null)" has not encouraged non-portable coding here (but then I try to stamp it out anyway), and letting the application continue to run has usually been more helpful than harmful. Normally upon seeing "(null)" in output where some meaningful string was expected, the software maintainer fixes the null pointer bug and no damage was done.
rbutterworth@watmath.waterloo.edu (Ray Butterworth) (03/22/89)
In article <9891@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes: > In article <4273@xyzzy.UUCP> throopw@agarn.dg.com (Wayne A. Throop) writes: > >I'd druther do something close to > > kill( getpid(), SIGSEGV ); > >in such a case. > > All I can say is, my experience with this has been that printing "(null)" > has not encouraged non-portable coding here (but then I try to stamp it > out anyway), and letting the application continue to run has usually been > more helpful than harmful. Normally upon seeing "(null)" in output where > some meaningful string was expected, the software maintainer fixes the > null pointer bug and no damage was done. Unfortunately many people will rely on this feature and believe it is actually part of the C language and library. (Consider all the postings to this group over the years that claim this fact.) A better idea than "<null)" would be a somewhat more obnoxious string such as: "a null character pointer was erroneously passed to printf". It would achieve the effect that you want and the one that Wayne wants.
throopw@agarn.dg.com (Wayne A. Throop) (03/25/89)
> gwyn@smoke.BRL.MIL (Doug Gwyn ) >> throopw@dg-rtp.dg.com (Wayne A. Throop) >> I'd druther do something close to >> kill( getpid(), SIGSEGV ); >> [..when a printf %s format is passed a null pointer..] > All I can say is, my experience with this has been that printing "(null)" > has not encouraged non-portable coding here (but then I try to stamp it > out anyway), and letting the application continue to run has usually been > more helpful than harmful. Ah. Good point: when a program is being developed, unexpected output in one form is as good as that in another. Adequate testing will discover these kinds of thing. But what I had in mind was that such an implementation of the printf family shouldn't make it into production code. People tend to scan things superficially, and may well miss such a thing as (null) in a column of entries of some sort (especially if something like N/A or whatnot is a valid entry). If the users don't happen to note it, they won't ask to have it fixed. Hence, I'd druther have a somewhat more attention-getting occurance for this error. Not that I claim Doug is "wrong"... these are largely taste issues after all. I just point out that his experience leading to his decision to print (null) seems pointed towards the development environment instead of the use environment. But "I could be wrong, you know!" (Note that with adequate debugging support, there is nothing to prevent continuing to the next error after raising the first... raising it as an error rather than as an unexpected output just "shouts louder" so to speak.) -- If someone tells me I'm not really conscious, I don't marvel about how clever he is to have figured that out... I say he's crazy. --- Searle (paraphrased) from an episode of PBS's "The Mind" -- Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw