[comp.sys.sgi] cc compiler warning question.

SERRER@NRCM3.NRC.CA (Martin Serrer) (11/17/90)

Hello c'ers,
  I am trying to define and access a data structure 'zero' which contains an
array of structures 'one' , the size of which is not know until run time. No
problem right?  When I compile this code I get warnings about 'illegal zero
sized structure member'. The code runs properly but I'm worried about the
warnings. What rules am I breaking?? (see the evidence below)

  Please be gentle as I am still learning about c.
Thanks in advance... Martin

BTW. this is on a 4D50/GT IRIX 3.2

-------------------------------evidence-----------------------------------------
% cat t.c
#include <stdio.h>

typedef struct { int a;        int b; } TINY;
typedef struct { TINY two;     int c; } SMALL;
typedef struct { SMALL *one[]; int f; } BIG;
BIG *zero;

main()
{       zero = (BIG *) malloc( (sizeof(BIG) + sizeof(SMALL) * 2) );
        zero->f = 1;
        zero->one[0].c = 2;
        printf("--- %i\n",zero->f);
        printf("--- %i\n",zero->one[0].c);
}

% cc t.c
ccom: Warning: t.c, line 18: illegal zero sized structure member: one
        } BIG;
      --^
ccom: Warning: t.c, line 28: struct/union or struct/union pointer required
        zero->one[0].c = 2;
      ---------------^
ccom: Warning: t.c, line 29: struct/union or struct/union pointer required
      printf("--- %i\n",zero->one[0].c);
      -------------------------------^

% t
--- 1
--- 2

+-----------------------------------------------------------------------------+
| Martin Serrer                           Systems Lab., Bldg. M2, Montreal Rd.|
| 613-993-9442                            National Research Council of Canada,|
| serrer@syslab.nrc.ca                    Ottawa,  Ontario,  Canada  K1A-0R6  |
+------------------- Software Rusts, Rust never Sleeps -----------------------+

karron@KARRON.MED.NYU.EDU (11/18/90)

>  I am trying to define and access a data structure 'zero' which contains an
>array of structures 'one' , the size of which is not know until run time. No

If I understand these things correctly ( and I may still not have it right)
your reference SMALL *one[] is the same as SMALL **one .

You have double indirection, and in non static code, the meaning of what you
actually allocate is a pointer to a pointer array pointing to an allocation of
small. This is pointed out in the K & R ansi c book, page 107 and following.
Get my point ?

When you allocate zero, *zero will point to an allocation consisting of
{ a pointer to a pointer of SMALL, int f}. You have not allocated storage
for small. You need another malloc statment like this:

zero->one=calloc(n,sizeof(SMALL));

Now you have allocated some space for the thing pointed to at one.
int n is the number of adjacent elements of SMALL you allocate. You would
reference them as

zero->one[m].two.a;

I use calloc to make certain that the allocated area is zero filled, and you
don't need to cast the return value.

>problem right?  When I compile this code I get warnings about 'illegal zero
>sized structure member'. The code runs properly but I'm worried about the
>warnings. What rules am I breaking?? (see the evidence below)

I don't know how the compiler can know this at compile time, but it sometimes
is smarter than I am.

I have had some problem with the . structure element offset operator and the
-> pointer operator. I think that somthing is wrong in my understanding or
the compiler, but the two are almost interchangable in too many contexts.

>
>  Please be gentle as I am still learning about c.
>Thanks in advance... Martin
>

I am still figuring this out. I have to wrangle the code to get it to
pass the compiler in ways I am not certain of.

>-------------------------------evidence----------------------------------------
   -
>% cat t.c
>#include <stdio.h>
>
>typedef struct { int a;        int b; } TINY;
>typedef struct { TINY two;     int c; } SMALL;
>typedef struct { SMALL *one[]; int f; } BIG;
>BIG *zero;
>
>main()
>{       zero = (BIG *) malloc( (sizeof(BIG) + sizeof(SMALL) * 2) );

This is bad practice. Your code only works by accident, as best as I can see.
You need two pointers, not one. You need a pointer for zero, and a pointer
for one. I don't see how you think you can get both allocated at once and
not know the address for the other.

>        zero->f = 1;
>        zero->one[0].c = 2;
>        printf("--- %i\n",zero->f);
>        printf("--- %i\n",zero->one[0].c);
>}
>
>% cc t.c
>ccom: Warning: t.c, line 18: illegal zero sized structure member: one
>        } BIG;
>      --^

Here, if you only specified a size for one, then you would allocate space
for it with the first malloc. In this setting, perhaps *one[] is NOT the
same as **one, and that may or may not be the issue. if you put in
*one[10], you would allocate an array consisting of 10 slots for pointers
to one. If you want to do it at run time, then you need two mallocs as I show
in here. I am not certain of the syntax differences in different settings
for **one vs *one[].

>ccom: Warning: t.c, line 28: struct/union or struct/union pointer required
>        zero->one[0].c = 2;
>      ---------------^

I get this error message a lot. It us usually fixed by replacing the . operator
with the -> operator. My feeling is that the .c should resolve the lvalue
of the pointer one[0] to a real value, but the compiler does not aggree with
my feeling. DBX allows you to use . and -> interchangeably. This issues
needs a higher authority.

ccom: Warning: t.c, line 29: struct/union or struct/union pointer required
>      printf("--- %i\n",zero->one[0].c);
>      -------------------------------^

Again, see my note above.

>
>% t
>--- 1
>--- 2

I don't know how you get an address for 2, even though it works. Is is
not referencing what you think, although you can still store/read its value
without a segmentation error. If you used calloc, you probably will get one
because your allocated region would be zero filled.

A good way to debug this stuff is to step through it with dbx, and look at
the addresses and what is stored at the address. It is very educational.
>
>+-----------------------------------------------------------------------------+
>| Martin Serrer                           Systems Lab., Bldg. M2, Montreal Rd.|
>| 613-993-9442                            National Research Council of Canada,|
>| serrer@syslab.nrc.ca                    Ottawa,  Ontario,  Canada  K1A-0R6  |
>+------------------- Software Rusts, Rust never Sleeps -----------------------+
>

These issues are really important when you have to allocate all of your data
structure in shared memory or Arenas.

I hope that this help, and that someone can help me with the questions I raised
in your code.

+-----------------------------------------------------------------------------+
| karron@nyu.edu (mail alias that will always find me)                        |
|                                         Dan Karron                          |
| . . . . . . . . . . . . . .             New York University Medical Center  |
| 560 First Avenue           \ \    Pager <1> (212) 397 9330                  |
| New York, New York 10016    \**\        <2> 10896   <3> <your-number-here>  |
| (212) 340 5210               \**\__________________________________________ |
| Please Note : Soon to move to dan@karron.med.nyu.edu 128.122.135.3  (Nov 1 )|
+-----------------------------------------------------------------------------+

moss@brl.mil (Gary S. Moss (VLD/VMB) <moss>) (11/19/90)

In article <032D013E619F0000A3@NRCNET.NRC.CA>, SERRER@NRCM3.NRC.CA (Martin Serrer) writes:
|> #include <stdio.h>
|> 
|> typedef struct { int a;        int b; } TINY;
|> typedef struct { TINY two;     int c; } SMALL;
|> typedef struct { SMALL *one[]; int f; } BIG;
|> BIG *zero;
|> 
|> main()
|> {       zero = (BIG *) malloc( (sizeof(BIG) + sizeof(SMALL) * 2) );
|>         zero->f = 1;
|>         zero->one[0].c = 2;
|>         printf("--- %i\n",zero->f);
|>         printf("--- %i\n",zero->one[0].c);
|> }
|> 
|> % cc t.c
|> ccom: Warning: t.c, line 18: illegal zero sized structure member: one
|>         } BIG;
|>       --^
You are declaring "one" as an array of unspecified, therefore zero size,
declare it as "SMALL **one;" instead.  In this context, there is a big
difference between the two declarations; the compiler knows how big a
"SMALL **" is. 


|> ccom: Warning: t.c, line 28: struct/union or struct/union pointer required
|>         zero->one[0].c = 2;
|>       ---------------^
You must use "->" rather than ".":
In the declaration "SMALL *one[];", one is an array of pointers to SMALL types.
Therefore, one[0] is a pointer and requires a "->" after it, not a ".".

|> ccom: Warning: t.c, line 29: struct/union or struct/union pointer required
|>       printf("--- %i\n",zero->one[0].c);
|>       -------------------------------^
Same thing as above.

You will also need to allocate storage for "one" separately from "zero":

if(	(zero = (BIG *) malloc( sizeof(BIG) )) == NULL
    ||	(zero->one = (SMALL *) malloc( sizeof(SMALL) * 2 )) == NULL )
	{ /* ALWAYS check success of malloc(3). */
	(void) fprintf( stderr, "No memory available!\n" );
	return 1;
	}

Of course, you *could* declare storage for zero like this:

BIG zero;

Rather than the first call to malloc, and leave your "."s as they are.

-Gary