[comp.lang.c] typedef-ing an array

pclark@SRC.Honeywell.COM (Peter Clark) (06/29/90)

Is it possible to specify a type definition like this:

typedef char foo[24];

foo bar;

and have type 'foo' be an array of 24 characters (or maybe 23 & a null), and
variable 'bar' an instance of this type?

Is there anyway to typedef an array (of a specific length)? Obviously, the
above declaration doesn't do it, or I wouldn't be asking. If the typedef
mechanism isn't sufficient (I don't think it is), how can this be done?

	Pete Clark
	Honeywell SRC
	Minneapolis, Mn

pclark@SRC.Honeywell.COM (Peter Clark) (06/29/90)

I wrote:

>Is there anyway to typedef an array (of a specific length)? Obviously, the
>above declaration doesn't do it, or I wouldn't be asking. If the typedef
>mechanism isn't sufficient (I don't think it is), how can this be done?

which wasn't specific enough. What I meant was, why doesn't this work:

-----------------------------------------

#include <stdio.h>

typedef char foo[29];

/* a string with 28 chars, add one for the NULL byte */
foo bar = "Hello World, this is my test";

void
  main()
{
  bar = "Silly old me";
  printf("%s\n",bar);
}
--------------------------------------------------

The initializer works fine, but the assignment inside main() doesn't.

	Pete Clark

writer@me.utoronto.ca (Tim Writer) (06/29/90)

In article <78633@srcsip.UUCP> pclark@SRC.Honeywell.COM (Peter Clark) writes:

>typedef char foo[29];
>foo bar = "Hello World, this is my test";

>void
>  main()
>{
>  bar = "Silly old me";
>  printf("%s\n",bar);
>}

>The initializer works fine, but the assignment inside main() doesn't.

You are forgetting the difference between an array and a pointer.  To quote
from K&RII (p. 99), "a pointer is a variable .... But an array name is not."
Therefore, you cannot assign an array, "Silly old me", to bar.  If `bar' were
a pointer, the compiler would simply assign the address of the first
character, `S' to `bar'.  But, `bar' is not a pointer.  Your compiler should
give a syntax error, something like `illegal lhs of assignment operator.'

To prove this to yourself, try this.

char	foo[29]="Hello world";

main()
{
	printf("%s\n",foo);
	foo="Goodbye world";
	printf("%s\n",foo);
}

If this does not generate a syntax error, your compiler is buggy.

Now try this.

typedef char	foo[29];

foo	bar="Hello world";

main()
{
	printf("%s\n",bar);
	strcpy(foo,"Goodbye world");
	printf("%s\n",bar);
}

Tim

roger@zuken.co.jp (Roger Meunier) (06/30/90)

In article <78633@srcsip.UUCP> pclark@SRC.Honeywell.COM (Peter Clark) writes:

 > What I meant was, why doesn't this work:
 >
 >-----------------------------------------
 >
 >#include <stdio.h>
 >
 >typedef char foo[29];
 >
 >/* a string with 28 chars, add one for the NULL byte */
 >foo bar = "Hello World, this is my test";
 >
 >void
 >  main()
 >{
 >  bar = "Silly old me";
 >  printf("%s\n",bar);
 >}
 >--------------------------------------------------

The variable "bar" is declared as a static string.  That is not the
same as declaring "char* bar" which is necessary for the assignment
statement.  I don't believe standard C even hints that strings are
copied by assignment statements.  A *pointer* to the literal string
is assigned to lhs, and in your example bar's type won't accept a
pointer.  Try 'char* bar = "Hello World, this is my test";' instead.
Clear as mud?
--
Roger Meunier @ Zuken, Inc.  Yokohama, Japan	(roger@zuken.co.jp)

chris@mimsy.umd.edu (Chris Torek) (07/03/90)

In article <78633@srcsip.UUCP> pclark@SRC.Honeywell.COM (Peter Clark) writes:
>> ... typedef char foo[24]; ...
>>Is there anyway to typedef an array (of a specific length)? Obviously, the
>>above declaration doesn't do it, or I wouldn't be asking. ...

The typedef above *does* do it.  After

	typedef char foo[24];

`foo' is an alias for a type that is `array 24 of char' and has size
24*sizeof(char)==24.  Thus, e.g.,

	printf("%d\n", sizeof(foo));

must print 42.

>What I meant was, why doesn't this work:

>typedef char foo[29];
>/* a string with 28 chars, add one for the NULL byte */
>foo bar = "Hello World, this is my test";
>void
>  main()
>{
>  bar = "Silly old me";
>  printf("%s\n",bar);
>}

>The initializer works fine, but the assignment inside main() doesn't.

The first error is `void main': it must (yes must) be `int main', even
if it never returns.  It may have either 0 arguments or two (int argc,
char *argv).

The second, more important error is the assignment inside main.  `bar'
is an object of type `array 29 of char'; a quoted string is an object
of type `array N of char' where N is one more than the number of characters
in the string.  `Silly old me' is 12 characters, so we have

	<object, array 29 of char, bar> =
		<object, array 13 of char, "Silly old me\0">;

The thing on the right hand side is in a value context, so it undergoes
The Famous Rule [repeat: in any value context an object of type `array
N of T' becomes a value of type `pointer to T' whose value is the address
of the first (0th) element of the array]:

	<object, array 29 of char, bar> =
		<value, pointer to char, 'S' in "Silly old me\0">

We now have a type mismatch---an array on the left and a pointer on the
right---as well as another constraint violation: arrays are not modifiable
lvalues and may not appear on the left of an assignment operator.

One obvious way to change it runs into another problem:

 1>	int main() {
 2>		foo local = "Silly old me";
		...

Now `local' is a local variable and the string on the right is an
initializer.  Line 2 here is NOT an executable statement, but rather a
declaration with an initializer.  Under ANSI C, aggregate initializers
are always permitted provided that the initializer is constant (which
this is).  (The string on the right of the equal sign is not in a value
context; it is in an initializer context.) If you hand this to a
Classic C compiler, however, you will get a complaint, because Classic
C allowed aggregate initializers only when the object being initialized
was global or static.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

toor@sun.udel.edu (Kartik S Subbarao) (07/03/90)

In article <25247@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
>In article <78633@srcsip.UUCP> pclark@SRC.Honeywell.COM (Peter Clark) writes:

>>void
>>  main()
>>{
>>  bar = "Silly old me";
>>  printf("%s\n",bar);
>>}
>
>>The initializer works fine, but the assignment inside main() doesn't.
>
>The first error is `void main': it must (yes must) be `int main', even
>if it never returns.  It may have either 0 arguments or two (int argc,
>char *argv).

(yes must)??!?!?!?!?! I beg to differ.

# include <stdio.h>

void main(int dumdum)
{
    printf("%d\n", dumdum);
    puts("Foobar");
}

works fine with gcc, and


# include <stdio.h>

void main(dumdum)
int dumdum;
{
    printf("%d\n", dumdum);
    puts("Foobar");
}

works fine with plain 'ol cc.

So you CAN have a) void main if you desire,
		b) only one argument to main.

-- 
toor@sun.acs.udel.edu -- (my summer address)

kdq@demott.COM (Kevin D. Quitt) (07/04/90)

In article <12433@sun.udel.edu> toor@sun.udel.edu (Kartik S Subbarao) writes:
>In article <25247@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
>>In article <78633@srcsip.UUCP> pclark@SRC.Honeywell.COM (Peter Clark) writes:
>

...

>>
>>The first error is `void main': it must (yes must) be `int main', even
>>if it never returns.  It may have either 0 arguments or two (int argc,
>>char *argv).
>
>(yes must)??!?!?!?!?! I beg to differ.

(examples deleted)

>So you CAN have a) void main if you desire,
>		b) only one argument to main.


    Should be int, (obviously not "must").  A void main returns garbage to
the shell, which is unfriendly.
-- 
 _
Kevin D. Quitt         demott!kdq   kdq@demott.com
DeMott Electronics Co. 14707 Keswick St.   Van Nuys, CA 91405-1266
VOICE (818) 988-4975   FAX (818) 997-1190  MODEM (818) 997-4496 PEP last

                96.37% of all statistics are made up.

karl@haddock.ima.isc.com (Karl Heuer) (07/04/90)

In article <12433@sun.udel.edu> toor@sun.udel.edu (Kartik S Subbarao) writes:
>In article <25247@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
>>The first error is `void main': it must (yes must) be `int main', even
>>if it never returns.  It may have either 0 arguments or two (int argc,
>>char *argv).
>
>(yes must)??!?!?!?!?! I beg to differ.
>[Sample code elided]

No, Chris was right (except that he forgot the second star in `char **argv').
Many compilers accept buggy code and even produce the intended answer, but
that doesn't make it right.  Not even if most compilers do it.

>So you CAN have a) void main if you desire,
>		b) only one argument to main.

In the most common implementation, both of these happen to work.  Neither is
Standard-conforming.  Both are likely to be caught by some future compiler.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

roger@everexn.uucp (Roger House) (07/04/90)

In <78633@srcsip.UUCP> pclark@SRC.Honeywell.COM (Peter Clark) writes:

>typedef char foo[29];

>/* a string with 28 chars, add one for the NULL byte */
>foo bar = "Hello World, this is my test";

>void
>  main()
>{
>  bar = "Silly old me";
>  printf("%s\n",bar);
>}

>The initializer works fine, but the assignment inside main() doesn't.

foo is of type "array of char".  The string "Silly old me" is of type "pointer
to char".  These are two different things.  In C you cannot assign a value to
an array by using the assignment operator "=".  The proper way to do what you
are trying to do in the first statement of main is this:

		strcpy(bar, "Silly old me");

							Roger House

chris@mimsy.umd.edu (Chris Torek) (07/05/90)

In article <25247@mimsy.umd.edu> I made two typing errors:
>... typedef char foo[24]; ... [foo] has size 24*sizeof(char)==24 ...
>	printf("%d\n", sizeof(foo));
>must print 42.

The last line above should read `24'.

>[main] may have either 0 arguments or two (int argc, char *argv).

The second argument should be `char **argv' (or equivalently `char *argv[]';
I recommend against the latter form since parameters declared as arrays
are not arrays, but this is the only place in C when a declaration does
not mean what it says, and this form leads programmers to believe that
arrays and pointers are `the same', which is not the case).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

chris@mimsy.umd.edu (Chris Torek) (07/20/90)

Although I already followed up to the original question, I should
correct something here:

In article <1990Jul3.231408.14315@everexn.uucp> roger@everexn.uucp
(Roger House) writes:
>... The string "Silly old me" is of type "pointer to char".

The type of a string constant is `array N of char', where N is one more
than the number of characters in the string% (the extra one is for the
final '\0' character).  In this case the type is `array 13 of char'.  The
string was, however, in a value context and as such undergoes the
usual transformation:

    In any value context, an object of type `array N of T' becomes a
    value of type `pointer to T' whose value is the address of the
    first (0th) element of the array.

This rule is extremely important.  Like the rule `a*b = b*a', it must
simply be memorised as a Fact Of C.  Given that and the rules of pointer
arithmetic and indirection, you can derive a consistent method for
dealing with arrays and pointers.
-----
% I am intentionally ignoring multibyte strings here, as they mainly
  serve to confuse the issue.

>In C you cannot assign a value to an array by using the assignment
>operator "=".

This is correct: an array is not a modifiable lvalue (i.e., it may not
be assigned to).  Note that an initialization (e.g., char x = 'f';)
is not an assignment (under ANSI X3.159-1989 at least; in Classic C
automatic initializers were semantically identical to assignments,
but under New C aggregates are permitted here).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

chris@mimsy.umd.edu (Chris Torek) (07/20/90)

In article <25585@mimsy.umd.edu> I wrote:
>% I am intentionally ignoring multibyte strings here, as they mainly
>  serve to confuse the issue.

Oops.  That should have read `multibyte characters'.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris