[comp.sys.mac.programmer] More on MPW C 3.0 question

ccc_ldo@waikato.ac.nz (02/19/90)

The story so far:

While porting a large C program between versions of MPW C, I came
across a strange quirk in the 3.0 compiler, which is summed up in
the following program:

	typedef unsigned char
	    Str255[256];

	main()
	  {
	    Str255
		temps, *tempp;

	    tempp = &temps;
	  }

When I try to compile this, the compiler throws up the following
error message:

	#
	#    tempp = &temps;
	#                  ?
	### Error 225 Incompatible types for assignment
	#-----------------------------------------------------------------------
		File "test.c"; Line 9
	#-----------------------------------------------------------------------

A number of people have made the same suggestion to me, viz, replace
the line

	    tempp = &temps;

with

	    tempp = temps;

Would you believe, this doesn't work? I get the exact same error, on the
same line.

Only one bright soul suggested the obvious, "brute force" solution--a type
cast. This does work. Here is the modified program, with an extra line added
to keep the compiler from optimising away the body of the routine completely:

	typedef unsigned char
	    Str255[256];

	main()
	  {
	    Str255
		temps, *tempp;

	    tempp = (Str255 *) &temps;
	    do_something_with(tempp);
	  }

It even generates the right code. *And* taking out the ampersand, as per
those other suggestions, makes no difference--it still compiles, and
still generates the same code.

To all those people who tried to explain to me that, in C, arrays are
actually just constant pointers--thanks, but I knew that. Also, all the
C compilers I've met, except one, have allowed me to use "&array" to mean
the same thing as "array", where "array" was an array variable. The MPW
3.0 compiler is no exception, as the following version of the troublesome
program demonstrates:

	typedef unsigned char
	    Str255[256];

	main()
	  {
	    Str255
		temps;
	    unsigned char
		*tempp;

	    tempp = &temps;
	    do_something_with(tempp);
	  }

This version also compiles without error, and generates the right code.

Thanks everybody for your help. But, the question remains: is this behaviour
a requirement of the ANSI C standard, or is it a bug in Apple's compiler?

Lawrence D'Oliveiro
Mac-hacker-in-residence
Computer Services Department, University of Waikato, Hamilton, New Zealand
All opinions expressed in this message are sacred to Epimetheus, the
    Greek god of hindsight.

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

In article <162.25dfe4b3@waikato.ac.nz> ccc_ldo@waikato.ac.nz writes:
>While porting a large C program between versions of MPW C, I came
>across a strange quirk in the 3.0 compiler, which is summed up in
>the following program:
>
>	typedef unsigned char Str255[256];

Uh, why not use MPW's own definition of Str255?  It's identical to the
above in effect, so I'm just curious.

>	main()
>	  {
>	    Str255
>		temps, *tempp;

"Str255 *tempp" makes no sense.  You can't have a pointer to an array
in C.  The compiler should choke on this, but it doesn't.  Instead,
your declarations should go:

	Str255 temps;
	StringPtr tempp;

>	    tempp = &temps;
>
>When I try to compile this, the compiler throws up the following
>error message:
>
>	#    tempp = &temps;
>	#                  ?
>	### Error 225 Incompatible types for assignment

Yep.  It's trrying to assign to a nonsensical type, so it's not too
surprising that it barfs.  However, if you declare as above and say:

	tempp = temps;

everything should be hunky dory.

I've noticed that MPW allows these nonsensical types myself; at one
point, I think in GetPattern or GetIndPattern, a parameter is defined
as a "Pattern *", which makes no sense since Pattern is just an array
of eight characters.  Nor will it let you generate an lvalue of this
nonsensical type by putting the address operator (&) in front of the
name of a variable of type Pattern.  The only thing you can do to make
it work is a type cast to (Pattern *).  Sounds pretty much the same as
your problem.  I think the compiler should disallow these silly
declarations in the first place, but if not, it should let you generate
pointers to arrays with the address operator.
-- 
Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com

This message does represent the views of Eclectic Software.

nick@lfcs.ed.ac.uk (Nick Rothwell) (02/20/90)

In article <10311@hoptoad.uucp>, tim@hoptoad (Tim Maroney) writes:
>"Str255 *tempp" makes no sense.  You can't have a pointer to an array
>in C.

Yes you can.

>Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com

		Nick.
--
Nick Rothwell,	Laboratory for Foundations of Computer Science, Edinburgh.
		nick@lfcs.ed.ac.uk    <Atlantic Ocean>!mcvax!ukc!lfcs!nick
~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~
		       ...als das Kind, Kind war...

morten@cs.qmw.ac.uk (Morten Ronseth) (02/20/90)

References: <162.25dfe4b3@waikato.ac.nz>

In article <10311@hoptoad.uucp> you write:
>In article <162.25dfe4b3@waikato.ac.nz> ccc_ldo@waikato.ac.nz writes:
>>While porting a large C program between versions of MPW C, I came
>>across a strange quirk in the 3.0 compiler, which is summed up in
>>the following program:
>>
>>	typedef unsigned char Str255[256];
>
>Uh, why not use MPW's own definition of Str255?  It's identical to the
>above in effect, so I'm just curious.

Agree. Why re-invent the wheel?

>
>>	main()
>>	  {
>>	    Str255
>>		temps, *tempp;
>
>"Str255 *tempp" makes no sense.  You can't have a pointer to an array
>in C.  The compiler should choke on this, but it doesn't.  Instead,
>your declarations should go:
>
>	Str255 temps;
>	StringPtr tempp;
>
>>	    tempp = &temps;
>>

Please, give me a break. Why can't you have pointers to arrays in C?
I mean, how do you explain `char *argv[]' and `char **argv'?
Surely, you must be familiar with this.

>>When I try to compile this, the compiler throws up the following
>>error message:
>>
>>	#    tempp = &temps;
>>	#                  ?
>>	### Error 225 Incompatible types for assignment
>
>Yep.  It's trrying to assign to a nonsensical type, so it's not too
>surprising that it barfs.  However, if you declare as above and say:
>
>	tempp = temps;
>
>everything should be hunky dory.

When using your declarations of temps & tempp, the assignement
`tempp = temps' will, on any smart compiler (read: gcc), generate
a warning: assignement between incompatible pointer types.
I assume you mean `*tempp = temps'.

I must admit, I'm no big fan of Apple's MPW C 3.0 compiler, and I guess this
is yet another example of its inadequacy. When I compiled the `erronous'
code (the part with the "address-of" assignement) using gcc (even did -Wall)
all the compiler complained about was me not declaring a return type
for main and that it had reached the end of a non-void function.
I think the problem is the MPW compiler.
(ever tried to compile gcc using MPW C 3.0? DON'T! it's a nightmare:
 I was *this* close to finish it when the MPW compiler suddenly fell
 over and told me it couldn't allocate anymore registers...(Apple are
 aware of this bug and it should be fixed in the next version...) also it 
 would only allow strings of lengths up to 509 (or so) chars. Even
 though this is the ANSI standard, there should be a flag for allowing
 longer strings. And, the preprocessor is too weak: only 11 levels of #include
 nesting (gcc has 77 I think) and unable to process some of the #define's
 in gcc (can't remember which files this happened in): some were to complex...
 Anybody from Apple reading this?)

Oh, by the way; I'm pretty sure that the definition of StringPtr
goes smth. like: `typedef Str255 *StringPtr'. Looks familiar? :-)
(Haven't looked it up though...)

>Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com
>
>This message does represent the views of Eclectic Software.

This message does *not* represent the views of QMW.
(Just a disclaimer in case I'm totally wrong; doan think so, tho'...)
-- 
==============================================================================
Morten Lerskau Ronseth

UUCP:     morten@qmw-cs.uucp       	   or ...seismo!mcvax!ukc!qmw-cs!morten
JANET:    morten@uk.ac.qmw.cs 	       Post:  Dept of Computer Science 
ARPA:     morten%qmw.cs@ucl-cs.arpa    		  Queen Mary and Westfield College 
Easylink: 19019285                     		  University of London
Telex:    893750 QMCUOL                		  Mile End Road
Fax:      +44 1 981 7517               		  London E1 4NS
Phone:    +44 1 975 5220               		  England

aruigrok@bnr.ca (Adrian C Ruigrok) (02/20/90)

In article <10311@hoptoad.uucp> tim@hoptoad.uucp (Tim Maroney) writes:
> 
> "Str255 *tempp" makes no sense.  You can't have a pointer to an array
> in C.  The compiler should choke on this, but it doesn't.  Instead,
> your declarations should go:
> 
>         Str255 temps;
>         StringPtr tempp;

This is all very fine and good, but it brings up another question that I 
never did figure out the answer to.  What if you want to read an array in 
as a resource?  Then you need a pointer to a pointer or a pointer to an 
array.  Could not the array pointer live in the master pointer and you 
just point to it?  I don't want to lock it down.  I was told this would 
work for an array of characters:
 
char **charResArray;

and you can access it by (charResArray *)[i]?  

This gets even better.  How can you declare a 2 dimensional array that is 
read in as a resource.
It would be really nice to be able to read in large lookup tables from 
resources instead of staticly declaring them.  However, I can't get my 
brain wrapped around these arrays yet!
Why can't I just declare it as above and reference it as
(charResArray *)[i][j];

the compiler complains that I cannot index this.  I think it is expecting 
the array element to be a pointer to an array.    Any insight in this 
matter would be helpful!
Thanks
Adrian

jrd@Apple.COM (John Robert Dance) (02/21/90)

Lawrence:
In your example, the array and the pointer are really are two 
incompatible types. The two types are:
    (char *)[256] = char *
In ANSI C this in an incompatible assignment.  (This is because the
address arithmetic for a pointer to a foo is different than for a pointer
to an array of foo.)
It is not a bug in MPW C.  The way to do what you want is to use the
cast, or use a StringPtr.

John Dance
Apple Computer 

rob@cs.mu.oz.au (Robert Wallen) (02/22/90)

In article <1629@sequent.cs.qmw.ac.uk> you write:
>References: <162.25dfe4b3@waikato.ac.nz>
>>"Str255 *tempp" makes no sense.  You can't have a pointer to an array
>>in C.  The compiler should choke on this, but it doesn't.  Instead,
>
>Please, give me a break. Why can't you have pointers to arrays in C?

Agreed.  However...

>I mean, how do you explain `char *argv[]' and `char **argv'?
>Surely, you must be familiar with this.

Well, yes I am.  char*argv[] is an array of POINTERS, not a pointer to an
array.  char**argv is a POINTER to a POINTER, not a pointer to an array.
C lets you use pointers as arrays but that doesnt make them the same thing.
You CAN have pointers to arrays but your example did not have anything to it
I think you are thinking of char (*argv)[]

>Oh, by the way; I'm pretty sure that the definition of StringPtr
>goes smth. like: `typedef Str255 *StringPtr'. Looks familiar? :-)
>(Haven't looked it up though...)

I hadnt looked it up, but I 'knew' it was wrong so I did and ...

/* from THINK_C 4.0 */

typedef unsigned char Str255[256];
typedef unsigned char * StringPtr,** StringHandle ;

levin@bbn.com (Joel B Levin) (02/23/90)

In article <2966@murtoa.cs.mu.oz.au> rob@murtoa.UUCP (Robert Wallen) writes:
|In article <1629@sequent.cs.qmw.ac.uk> you write:
|>Oh, by the way; I'm pretty sure that the definition of StringPtr
|>goes smth. like: `typedef Str255 *StringPtr'. Looks familiar? :-)
|>(Haven't looked it up though...)
|
|I hadnt looked it up, but I 'knew' it was wrong so I did and ...
|
|/* from THINK_C 4.0 */
|
|typedef unsigned char Str255[256];
|typedef unsigned char * StringPtr,** StringHandle ;

Well, here is MPW 3.0 or 3.1 (I'm not sure which):

typedef unsigned char
Str255[256],Str63[64],Str31[32],Str27[28],Str15[16],*StringPtr,**StringHandle;

I'm not sure what this proves, though...

=
Nets: levin@bbn.com  |  "There were sweetheart roses on Yancey Wilmerding's
 or {...}!bbn!levin  |  bureau that morning.  Wide-eyed and distraught, she
POTS: (617)873-3463  |  stood with all her faculties rooted to the floor."

rcfische@polyslo.CalPoly.EDU (Raymond C. Fischer) (02/23/90)

morten@cs.qmc.ac.uk (Morten Ronseth) writes:
>In article <10311@hoptoad.uucp> you write:
>>ccc_ldo@waikato.ac.nz writes:
>>>	main() {
>>>	    Str255
>>>		temps, *tempp;
>>
>>"Str255 *tempp" makes no sense.  You can't have a pointer to an array
>>in C.  The compiler should choke on this, but it doesn't.  Instead,
>>your declarations should go:

[edited]

>Please, give me a break. Why can't you have pointers to arrays in C?
>I mean, how do you explain `char *argv[]' and `char **argv'?
>Surely, you must be familiar with this.

Although it is a subtle point, C does NOT have pointers to arrays.
When an array is reference by its name, the name evaluates to a pointer
to the array's first element.  This is a pointer to an element of the
array, not the entire array.  Thus, the type is 'pointer to element'
rather than 'pointer to array'.  Common 'features' of this are the 
facts that C arrays do not have any bounds and a pointer variable can
be used just like an array variable.

One interesting effect of this is the following code.
	int  i, x[20];
	i = 5;
	i[x] = 0;
No, I did not make a mistake.  The [] is an operator that is equivalent
to *(i+x) and so the order doesn't really matter.  DON'T DO THIS however; 
it is incredibly nasty programming style.

Ray Fischer
rcfische@polyslo.calpoly.edu

bowman@reed.UUCP (Eric Bowman) (02/23/90)

MPW C 3.0 and Think C Str255 are identical (in function).

BoBo

bowman@reed.UUCP (Eric Bowman) (02/23/90)

I'm not a C theoretician, but there is definitely a distinction between
a pointer to a pointer and a pointer to a so-called array.  An array really
is a pointer, but since you never change what an array pointer points to, i.e.
	char	a[5],b[5];

	<code>
	a=b;

it is useful to make a distinction between a pointer in the traditional sense
and a pointer defined as an array.  Thus a pointer to "a", i.e.

	char **c=&a;

is not necessarily mislabled as a "pointer to an array."  In a strictly tech-
nical and sematic environment, I suppose so, but in a practical sense its
meaningful.

BoBo
(bowman@reed.bitnet)
my .sig got trashed.

morten@cs.qmw.ac.uk (Morten Ronseth) (02/23/90)

References: <162.25dfe4b3@waikato.ac.nz> <10311@hoptoad.uucp> <1629@sequent.cs.qmw.ac.uk>

In article <2966@murtoa.cs.mu.oz.au> you write:
>In article <1629@sequent.cs.qmw.ac.uk> you write:
>>References: <162.25dfe4b3@waikato.ac.nz>
>Well, yes I am.  char*argv[] is an array of POINTERS, not a pointer to an
>array.  char**argv is a POINTER to a POINTER, not a pointer to an array.
>C lets you use pointers as arrays but that doesnt make them the same thing.
>You CAN have pointers to arrays but your example did not have anything to it
>I think you are thinking of char (*argv)[]

Oops, yes, you are absolutely right. The correct notation *should* be (*argv)[].
But, according to K&R, there is such a strong relationship between pointers
and arrays that they really should be treated simultanously (page 93).

				Morten.
-- 
==============================================================================
Morten Lerskau Ronseth

UUCP:     morten@qmw-cs.uucp       	   or ...seismo!mcvax!ukc!qmw-cs!morten
JANET:    morten@uk.ac.qmw.cs 	       Post:  Dept of Computer Science 
ARPA:     morten%qmw.cs@ucl-cs.arpa    		  Queen Mary and Westfield College 
Easylink: 19019285                     		  University of London
Telex:    893750 QMCUOL                		  Mile End Road
Fax:      +44 1 981 7517               		  London E1 4NS
Phone:    +44 1 975 5220               		  England