Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

sprintf() bug?

13 views
Skip to first unread message

David Palmer

unread,
Jan 27, 1988, 7:51:00 PM1/27/88
to
In article <4VzXREy00...@andrew.cmu.edu> rs...@andrew.cmu.edu (Richard Siegel) writes:
>Additional recommendation: to avoid having to use CtoPstr, just use the "\p"
>at the beginning of the string:
>
> sprintf(tempstring, "%s %f %s %f", "\pthe square of ", x, "is", (x *x));
> DrawString(tempstring);

This will not work in any C which I understand. What will be put into
tempstring is a null terminated string something like:
\016the square of ;&91/z\234dsi 5.00000 is 25.00000
where \016 is the first character in a Pascal string of length 14,
;&91/z\234dsi represents random garbage in the memory following the
string, which only ends when there happens to be a byte containing \0,
and the remainder is self explanatory.

"\pfoo" does not represent a C-string whose first character is '\p', it
represents a Pascal string, a one-byte length followed by that many
characters. Sprintf is passed an address as its argument, and it
expects that address to be of a C-string. By the same token, using
a format string of "\p%s %f %s %f" will also fail to work.


David Palmer
pal...@tybalt.caltech.edu
...rutgers!cit-vax!tybalt.caltech.edu!palmer
"Every day it's the same thing--variety. I want something different."

Gray Watson

unread,
Feb 1, 1988, 1:04:14 PM2/1/88
to
> sprintf(tempstring, "%s %f %s %f", "\pthe square of ", x, "is", (x *x));
> DrawString(tempstring);

Article <53...@cit-vax.Caltech.Edu> stated that the lines above "will not work
in any C which [he] understand[s]". Tempstring should, according the article
be equal to "\016the square of" followed by random garbage.

Well I don't know what version of C you are using but the example WILL work:

Sscanf should, like strcat, strcpy, etc. pad any string produced with
with a \0 (NULL) character. If it doesn't then it is your compiler's fault.
The \p (which for non-Mac routines does insert a \016) is needed for
the Mac interface. The first character in the string you send to DrawString
should be the value of the length of the string or should be \p or \016:

If you are setting up a window title to be "Hello Dolly" the string you
should give the OpenWindow call (or whatever it is) should be
"\011Hello Dolly" with \011 being the length of "Hello Dolly",
but "\pHello Dolly" saves you from recounting the length of the string
if you change it a lot.


Also when any of the Mac's ROM based file routines return a file name
string it doesn't have a \0 (NULL) at the end of the char array but instead
the value of first character is the length of the string.

To translate from a Mac returned string into correct C format:

If file_name[20] is returned I do a:
file_name[file_name[0]] = 0; /* punch the string-end with a null */
and refer to the string as &file_name[1]

Or if you have memory and speed to burn:
If temp[20] is returned:
You can do a strncpy(file_name,&temp[1],temp[0]);
Which makes file_name be a correct C string with the returned name.


Have fun...

Jim Cathey

unread,
Feb 2, 1988, 12:26:09 PM2/2/88
to
In article <9...@cadre.dsl.PITTSBURGH.EDU> c...@cadre.dsl.pittsburgh.edu.UUCP (Gray Watson) writes:
>> sprintf(tempstring, "%s %f %s %f", "\pthe square of ", x, "is", (x *x));
>> DrawString(tempstring);
>
>Article <53...@cit-vax.Caltech.Edu> stated that the lines above "will not work
>in any C which [he] understand[s]". Tempstring should, according the article
>be equal to "\016the square of" followed by random garbage.

> The \p (which for non-Mac routines does insert a \016) is needed for


>the Mac interface. The first character in the string you send to DrawString
>should be the value of the length of the string or should be \p or \016:
>
>If you are setting up a window title to be "Hello Dolly" the string you
> should give the OpenWindow call (or whatever it is) should be
> "\011Hello Dolly" with \011 being the length of "Hello Dolly",
> but "\pHello Dolly" saves you from recounting the length of the string
> if you change it a lot.

To add to the confusion...

It is my understanding that in Aztec C (the first place I saw the \p notation)
something like "\pfoobar" told the C compiler to count the length of the
quoted string and place it in an extra byte at the front of the string. The
string was still null terminated as well. Thus "\pthe square of " yielded
a hidden 16-byte storage area initialized with "\016the square of \0" (don't
forget that \0xx is OCTAL). So, the sprintf example above should cough up
the storage area tempstring filled with "\016the square of xxxxxx is yyyyyy\0"
which would draw on the screen "the square of " since the \016 would tell
DrawString to use only 14 characters out of tempstring. The correct way
would be to use the CtoPStr function against tempstring, forgetting the \p
stuff completely (since this scenario is exactly what this function is for).
The \p notation is for string literals that aren't to be massaged later by
C string functions before being sent to the Toolbox.

Of course, LSC might do something differently, like it could treat \p as a
literal constant character that glue versions of DrawString (et. al.) could
notice and then do internal CtoPStr operations (gackkk!). This is somewhat
in accord with how I read the second poster's information. I don't think
LSC does this though, though I don't have it available to check.

I thought the manual for Aztec C was reasonably clear on the whole matter,
although I don't remember it it used examples.

+----------------+
! II CCCCCC ! Jim Cathey
! II SSSSCC ! ISC Systems Corp.
! II CC ! TAF-C8; Spokane, WA 99220
! IISSSS CC ! UUCP: uunet!iscuva!jimc
! II CCCCCC ! (509) 927-5757
+----------------+
"With excitement like this, who is needing enemas?"

Richard Siegel

unread,
Feb 3, 1988, 11:01:54 AM2/3/88
to

"Of course, LSC might do something differently, like it could treat \p as a
literal constant character that glue versions of DrawString (et. al.) could
notice and then do internal CtoPStr operations (gackkk!). This is somewhat
in accord with how I read the second poster's information. I don't think
LSC does this though, though I don't have it available to check."

LightspeedC doesn't do this. The exact mechanism I don't know, but what
happens with "\pfoo" is that you get a 4-byte space with a length byte at the
beginning followed by the characters, which is suitable for passing to ROM
traps. There's no glue involved.

MPW and Aztec, on the other hand, allow you to pass C strings to ROM calls;
they *do* have glue. For EVERY SINGLE trap that takes a string, they have
glue.
Icky.

--Rich

Ted Johnson

unread,
Feb 3, 1988, 12:18:38 PM2/3/88
to

I have found a solution to my problem. To print out floats and
integers in Lightspeed C, use the following:

char s[256];
float x= 3.3;
int y = 1;

sprintf(s, "Identity number %d: %f squared = %f",
x, (x * x));

/*To print this in a window...*/
DrawString(CtoPstr(s));

/*Or to print this in the "stdio window", do...*/
printf(s);


BTW, I tried to do this same thing using a Str255 variable instead of
a char array (in a variation of the above code), but it bombed...

Also, using DrawString() *should* also work for a DA's window (after
you first recompile the sprintf/scanf library as a DA, so that things
are referenced off of A4 instead of A5), but it doesn't. :-(

Any theories or workarounds are welcomed!

-T("All I want to do is print the value of a float in a DA's window!")ed

Joel B Levin

unread,
Feb 3, 1988, 12:58:03 PM2/3/88
to
In article <MW1oTmy00...@andrew.cmu.edu> rs...@andrew.cmu.edu (Richard Siegel) writes:
:MPW and Aztec, on the other hand, allow you to pass C strings to ROM calls;
:they *do* have glue. For EVERY SINGLE trap that takes a string, they have
:glue.
:Icky.

As of MPW 2.0, you can avoid the glue in most cases, because two
things have been added:

1. In the #include files, for each trap where the only differences
between the "glued" version and the trap are string type and calling
sequence, a definition has been added which invokes the trap directly,
e.g.,

SetWTitle (theWindow, cString);

gets you some glue, but

SETWTITLE (theWindow, PStringPtr);

gets you the trap without glue. This doesn't work for OS calls which
don't use the stack; there you always need glue, I imagine even in LSC.

2. The compiler recognizes the "special" character \p at the head of a
string constant and translates it to a length byte, so you can now say

SETWTITLE (theWindow, "\pNew title");

I have been playing in my spare time with the problem of translating
LSC into MPW (I don't have LSC or a manual, so I'm half blind) --
specifically, TransSkel, TransDisplay, and TransEdit and their demos.
It has been most educational. Before I learned of these new features
of MPW 2.0, it was a lot of work; this has made it much easier. When
I have done, I'll probably write up the lessons I've learned so it is
easier for someone else to do this. (Unless, of course, someone has
written a translator?)

/JBL

UUCP: {harvard, husc6, etc.}!bbn!levin
ARPA: le...@bbn.com

Wayne Pollock

unread,
Feb 6, 1988, 1:33:32 AM2/6/88
to
Funny; I thought for sure it would work. I haven't tested it, but it would
seem to me that the \p is interpreted in some sort of glue routine, well after
the string is constructed. That is, when a string containing "\p" is passed
to some toolbox routine, AT THAT TIME the length of the string is determined,
and substituted for the first byte. If it works this way, then the example
given would indeed work as desired.

I'm not sure how it could work this way, unless LSC reserves some char code
(such as 255) as a marker; of course this would be incompatible with C syntax.
Anybody know for certain, or willing to crash his mac to check this out?

Wayne Pollock (The MAD Scientist) pol...@usfvax2.usf.edu.UUCP
Usenet: ...!{ihnp4, cbatt}!codas!usfvax2!pollock
GEnie: W.POLLOCK

David Palmer

unread,
Feb 8, 1988, 1:24:21 PM2/8/88
to
In article <9...@cadre.dsl.PITTSBURGH.EDU> c...@cadre.dsl.pittsburgh.edu.UUCP (Gray Watson) writes:
>> sprintf(tempstring, "%s %f %s %f", "\pthe square of ", x, "is", (x *x));
>> DrawString(tempstring);
>
>Article <53...@cit-vax.Caltech.Edu> stated that the lines above "will not work
>in any C which [he] understand[s]". Tempstring should, according the article
>be equal to "\016the square of" followed by random garbage.
>
>Well I don't know what version of C you are using but the example WILL work:
>
> Sscanf should, like strcat, strcpy, etc. pad any string produced with
>with a \0 (NULL) character. If it doesn't then it is your compiler's fault.
> The \p (which for non-Mac routines does insert a \016) is needed for
>the Mac interface. The first character in the string you send to DrawString
>should be the value of the length of the string or should be \p or \016:

I don't know whether this has been hashed to death (our news-feed has
been down for a week) but you are missing the point.
The string produced by "\pthe square of " is NOT null terminated (it is
a Pascal string, and so the length is specified by a byte at the beginning,
rather than a terminator at the end). Sprintf requires null-terminated
(C) strings, and so when it is passed a pointer to a Pascal string,
it assumes that the string goes on until it hits a \0, somewhere
out in random memory beyond the end of the string. It is true
that the string 'tempstring' will be null terminated by sprintf,
but the puropose of this exercise was to get a Pascal string. If you
pass 'tempstring' to a function which uses Pascal strings, it will see
only the first 14 (specified by the \016 in octal) characters:
"the square of "

>If you are setting up a window title to be "Hello Dolly" the string you
> should give the OpenWindow call (or whatever it is) should be
> "\011Hello Dolly" with \011 being the length of "Hello Dolly",

(^ this should be \013, because \xxx requires xxx to be in octal)


> but "\pHello Dolly" saves you from recounting the length of the string
> if you change it a lot.

True, but the '\p' in "\pHello Dolly" is just a directive to tell the
compiler to count the characters for itself, and the string is stored in
memory as "\013Hello Dolly", with no null termination.

>
>To translate from a Mac returned string into correct C format:
>
>If file_name[20] is returned I do a:
> file_name[file_name[0]] = 0; /* punch the string-end with a null */
> and refer to the string as &file_name[1]
>
>Or if you have memory and speed to burn:
> If temp[20] is returned:
> You can do a strncpy(file_name,&temp[1],temp[0]);
> Which makes file_name be a correct C string with the returned name.

Or you can use the procedures PtoCStr() and CtoPStr() which are included
in most compilers.

Gregory Dudek

unread,
Feb 16, 1988, 5:28:25 PM2/16/88
to
Just to correct some apparent misinformation that has been propagated
on this subjec...

In article <53...@cit-vax.Caltech.Edu> pal...@tybalt.caltech.edu.UUCP (David Palmer) writes:
>In article <9...@cadre.dsl.PITTSBURGH.EDU> c...@cadre.dsl.pittsburgh.edu.UUCP (Gray Watson) writes:
>>> sprintf(tempstring, "%s %f %s %f", "\pthe square of ", x, "is", (x *x));
>>> DrawString(tempstring);

[ etc, etc ]


>>
>
>The string produced by "\pthe square of " is NOT null terminated (it is
>a Pascal string, and so the length is specified by a byte at the beginning,

>...


>True, but the '\p' in "\pHello Dolly" is just a directive to tell the
>compiler to count the characters for itself, and the string is stored in
>memory as "\013Hello Dolly", with no null termination.
>

Aztec C produces a C-string *WITH* a null terminator when it sees:
"\Pfoo". In other words it's a legal Pascal string but has an EXTRA
character (null) that Pascal routines won't notice, thus making it a
legal C-string also. This seems like a very sensible idea since C
routines invoked on it won't blow up & things like strcpy still work.
I don't know what other complers do, but I would be seem reasonable if they
did the same.
Of course, this doesn't solve the original poster's problem. He should
use something like:
sprintf(tmp,"%s %d ect",...); DrawString(CtoPascal(tmp));
where CtoPascal is appropriately defined (most compilers include
a library routine that does this).

As for glue routines, Aztec C uses them only for *some* ROM traps; most
are defined as straight ROM entries.

Greg Dudek
--
Dept. of Computer Science (vision group) University of Toronto
Reasonable mailers: du...@ai.toronto.edu
Other UUCP: {uunet,ihnp4,decvax,linus,pyramid,
dalcs,watmath,garfield,ubc-vision,calgary}!utai!dudek
ARPA: user%ai.toro...@relay.cs.net

0 new messages