[comp.sys.mac.programmer] Quick ThinkC String question...

waylonis@banana.cis.ohio-state.edu (Mr Waylonis) (02/14/90)

Hi,

I'm having a problem getting ThinkC to accept the following:

procedureX()
{
	Str255	myString;

	myString = "\pExample string";
}

which a reference book said was correct.  I need to be able to set the
string to different values, so I can't say:

	Str255	myString = {"\pExample string"};

Any suggestions?

Thanks,
Dan




-=-
Dan Waylonis, resplendent grad student          Home Sweet Home:
Ohio State University, Dept. of CS  | 2251 Buckley Rd. Cols., OH 43220-4613
2036 Neil Ave., Cols., OH 43210-1277| (614) 459-7326
Email: waylonis@cis.ohio-state.edu  | "No matter where you go, there you are."

beard@ux1.lbl.gov (Patrick C Beard) (02/14/90)

In article <77108@tut.cis.ohio-state.edu> <waylonis@cis.ohio-state.edu> writes:
#Hi,
#
#I'm having a problem getting ThinkC to accept the following:
#
#procedureX()
#{
#	Str255	myString;
#
#	myString = "\pExample string";
#}
#
#which a reference book said was correct.

At certain times I've used strcpy(myString, "\pExample string");  MPW C
certainly allows this, as a length byte and null are generated in 
MPW C's string constants.  I'm not sure if THINK C's have nulls.  And
obviously this won't work in general for all pascal strings.  How about:

pstrcpy(StringPtr dest, StringPtr src)
{
	register short len = src[0];

	dest[0] = len;		/* save length. */
	while(len--) *++dest = *++src;
}

This should be general enough...  (please no flames, I composed this here.)

-------------------------------------------------------------------------------
-  Patrick Beard, Macintosh Programmer                        (beard@lbl.gov) -
-  Berkeley Systems, Inc.  ".......<dead air>.......Good day!" - Paul Harvey  -
-------------------------------------------------------------------------------

sdh@flash.bellcore.com (Stephen D Hawley) (02/14/90)

In article <77108@tut.cis.ohio-state.edu> <waylonis@cis.ohio-state.edu> writes:
>Hi,
>
>I'm having a problem getting ThinkC to accept the following:
>procedureX()
>{
>	Str255	myString;
>
>	myString = "\pExample string";
>}

Try:

procedureX()
{
	char *myString;

	myString = "\pExample string";
}

Str255 is an array type.  When you say "Str255 myString" you are actually
saying "create an array of 256 characters named myString".  When you do
the assignment, you are asking Think C to do a Pascal string copy at
runtime.  This is undefined behavior for arrays in C.

My example just does a pointer assignment.  Beware that myString is a
char * not an unsigned char *.  If you declare it as an unsigned char * you
will get a type clash, but if you don't you have to be sure to cast the first
byte to an unsigned char if you use it as a length (otherwise it'll get
sign extended).

Steve Hawley
sdh@flash.bellcore.com


A noun's a special kind of word.
It's ev'ry name you ever heard.
I find it quite interesting,
A noun's a person place or thing.

rotberg@dms.UUCP (Ed Rotberg) (02/15/90)

From article <77108@tut.cis.ohio-state.edu>, by waylonis@banana.cis.ohio-state.edu (Mr Waylonis):
> Hi,
> 
> I'm having a problem getting ThinkC to accept the following:
> 
> procedureX()
> {
> 	Str255	myString;
> 
> 	myString = "\pExample string";
> }
> 
> Any suggestions?

Offhand, I can't say whether the above syntax is legal or not as I'm more of a
"working man's" C programmer, and not a theoretician.  However, as the compiler
dosn't like it, you need to write a small routine like:

void pStrcpy(dst,src)	/* I myself like (src,dst) but it's just not C!! */
Str255 *dst,*src;
{
	int i;

	for(i = (unsigned char)(*src); i >=0; --i) /* cast whenever in doubt */
		*dst++ = *src++;
}

Then
	myString = "\pExample string";
becomes
	pStrcpy(myString,"\pExample string");

Not precisely elegant, but it'll work.

	- Ed Rotberg -

omullarn@oracle.oracle.com (Oliver Mullarney) (02/15/90)

In article <20011@bellcore.bellcore.com> sdh@flash.UUCP (Stephen D Hawley) writes:
>In article <77108@tut.cis.ohio-state.edu> <waylonis@cis.ohio-state.edu> writes:
>>Hi,
>>
>>I'm having a problem getting ThinkC to accept the following:
>>procedureX()
>>{
>>	Str255	myString;
>>
>>	myString = "\pExample string";
>>}
>
>Try:
>
>procedureX()
>{
>	char *myString;
>
>	myString = "\pExample string";
>}
>

This is just a little dubious; no space is being allocated anywhere, so
this should not be used in a general case. It will work for the given
situation, but not once you drop up one level on the stack from where
the assignment is made (literals are defined on the stack, right?).

What I would do is:
procedureX()
{
	char *myString = (char *)malloc(256); /* can index 0 to 255 */

       strcpy(myString,"Example string");
       c2pstr(myString); /* effectively turns it into an Str255 */

       ...
       p2cstr(myString); /* unnecessary, but why not be tidy :-) */
       free (myString);
}

This is a little more general, and safe.

  Oliver


| Oliver Mullarney     |         "Death wears a big hat,                     |
| Oracle Corporation   |          'cos he's a big bloke"                     |
| omullarn@oracle.com  |                 Tokyo Storm Warning, Elvis Costello |
 --------------- "Universally acknowledged to work just fine" ----------------

dowdy@apple.com (Tom Dowdy) (02/16/90)

[ several people give suggestions for copying strings via procedures ]

Here are some macros for doing similar things:

#define PSTRCPY(P1, P2) BlockMove(P2, P1, P2[0]+1)

and also

#define PSTRCAT(P1, P2) \
   BlockMove(&P2[1], &P1[(P1[0]+1)], P2[0]); \
   P1[0] += P2[0];

Some cautions about these, however.  First off, neither of them do any 
kind of error checking.  In the first case, this usually isn't a problem 
when you are tossing Str255s around.  In the second case, things *can* get 
more hairy, but this is the case of having strong requirements on the 
caller rather than in the called routine.  As long as one is aware of what 
is going on, this isn't a problem.  The second macro probably isn't the 
most efficient way to code this, and no doubt some C person will tell me 
as much, but I almost never use PSTRCAT except in debugging code.

However, there is one *serious* problem to watch out for.  I hope this is 
the correct reason for this.  In MPW C, the "\p" directive isn't evaulated 
until late in the code gen, so at the macro level, taking the first 
position in the array as a length results in the value '\' rather than in 
the length of the string.  The result of this is that you can't do 
PSTRCPY(myString, "\pTesting");  This can be annoying, but since all my 
strings come out of resources (as they should in final code), I work 
around it when I have to.  I don't know if this also happens in Think C, 
it may be part of the ANSI C spec.

 Tom Dowdy                 Internet:  dowdy@apple.COM
 Apple Computer MS:81EQ    UUCP:      {sun,voder,amdahl,decwrl}!apple!dowdy
 20525 Mariani Ave         AppleLink: DOWDY1
 Cupertino, CA 95014       
 "The 'Ooh-Ah' Bird is so called because it lays square eggs."

tim@hoptoad.uucp (Tim Maroney) (02/16/90)

In article <1990Feb14.210352.28118@oracle.com> omullarn@oracle.com
(Oliver Mullarney) writes:
>>procedureX()
>>{ 	char *myString;
>>	myString = "\pExample string";
>>}
>>
>
>This is just a little dubious; no space is being allocated anywhere, so
>this should not be used in a general case. It will work for the given
>situation, but not once you drop up one level on the stack from where
>the assignment is made (literals are defined on the stack, right?).

No, generally speaking, they're allocated in global space.  You can
give a compiler directive in MPW to make them allocated in code space,
though; this is useful mostly in XCMDs and XFCNs.  I don't know of any
Mac C compilers that put string literals on the stack.  Think about the
code the compiler would have to generate and you'll see why.

Of course, all the discussion here has missed the real point, which is
that you almost always should avoid string literals on the Mac (except
in XCMDs and XFCNs, where they're considered kosher, because someone
moving the XCMD into another stack may forget to move any associated
'STR ' and 'STR#' resources, and they may have to be renumbered to avoid
conflicts).  Instead, use GetString and GetIndString to get your string
constants; this will make it much easier to move your code to other
languages.

However, in the immortal words of Amanda Walker, if you're making mud
pies, it doesn't matter how much sugar you use; if you're just doing a
quick and dirty utility or something which you are reasonably sure will
always be local to your site, go ahead and use the literals.

Finally, the most useful string manipulation utility is BlockMove.  Use
it often and without compunction.
-- 
Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com

FROM THE FOOL FILE:
"The negro slaves of the South are the happiest, and, in some sense, the
 freest people in the world.  The children and the aged and infirm work not
 at all, and yet have all the comforts and neccessaries of life provided for
 them." -- George Fitzhugh, CANNIBALS ALL! OR, SLAVES WITHOUT MASTERS, 1857