Re: [cc65] Another wish: Unsized Arrays in Structures

Date view Thread view Subject view

From: Spiro Trikaliotis (trik-news_at_gmx.de)
Date: 2003-01-23 10:42:06


Hallo Tim,

Tim Schürmann schrieb:

> Spiro Trikaliotis schrieb:
>
> > Groepaz: There is a difference. In your code, TestStruct contains
> > a pointer to some area. This is not true with Christian's wanted
> > solution.
> >
> > Look at this:
> >
> > TestStruct *a = malloc(sizeof(TestStruct)+sizeof(unsigned char)*100);
>
> > With this, you get a TestStruct which contains 100 elements (0..99)
> > [in case the 0 does not work, and David's suggestion has to be applied,
> > it is 101, ie., 0..100].
>
>
> Sorry, but i don't understand your argumentation.
> What you got there is, that TestStruct points to a beginning of the
> allocated memory of 1 TestStruct (why do you "malloc" the TestStruct?
> TestStruct already exist)

well, the type TestStruct exists, but there isn't memory for it.

Look at my definition:

> > TestStruct *a = malloc(sizeof(TestStruct)+sizeof(unsigned char)*100);

I only define a pointer to a TestStruct (TestStruct *) named a. For this,
I reserve the memory for the TestStruct plus 100 bytes at the end.

This is not true for Groepaz solution: Here, you reserve memory for the
TestStruct (which contains x Bytes for a pointer to a buffer of chars!)
plus the 100 bytes at the end. This is x bytes more.

> plus 100 Elements of unsigned char. So, does data
> point automaticly to the right allocated "char-Memory"? If this is true,
> the same line should work with Groepaz solution.

No, there is no pointer to the right allocated "char-memory". In fact,
you do not need anymore pointer.

Look at this:

With my solution, the TestStruct looks like

 +-----------------------+
 | unsigned char width   |
 +-----------------------+
 | unsigned char height  |
 +-----------------------+
 | unsigned char data[0] |
 +-----------------------+
 | unsigned char data[1] |
 +-----------------------+
 | unsigned char data[2] |
 +-----------------------+
 | ...      ...  ...     |
 .                       .
 .                       .
 .                       .
 | ...      ...  ...     |
 +-----------------------+
 | unsigned char data[99]|
 +-----------------------+
}

With groepaz' solution, you have

 +-----------------------+
 | unsigned char width   |
 +-----------------------+
 | unsigned char height  |
 +-----------------------+
 | unsigned char *data   |    ----------------------------+
 +-----------------------+                                |
                                                          |
You have to reserve memory for data separately, so        |
you get some more memory:                                 |
                                                          |
 +-----------------------+                                |
 | unsigned char _[0]    |   <----------------------------+
 +-----------------------+
 | unsigned char _[1]    |
 +-----------------------+
 | unsigned char _[2]    |
 +-----------------------+
 | ...      ...  ...     |
 .                       .
 .                       .
 .                       .
 | ...      ...  ...     |
 +-----------------------+
 | unsigned char _[99]   |
 +-----------------------+

> My C-Standard book (german version of Kernighan and Richie) says, that
>
> char a[];
> and
> char *a;
>
> are the same. Arrays acts like pointers (btw: are arrays realised as
> pointers?). That's why you could write a[i] or *(a+i) and if pa is a
> pointer and a the array you can do
> pa=a
> and
> pa++
> to get the next element.

*sigh* The old array vs. pointer discussion...

No, pointer and arrays are not (always) the same. In this case, the are not.
They appear to be the same because C defines an implicit cast from
an array to a pointer.

1. char a[];
and
2. char *a;

seem to be the same, yes. Both defined something named "a" where I can
put something into. Both don't reserve memory for the things to store -
it seems, but this is not true! While 1. doesn't reserve any memory,
with 2., there is memory reserved for one pointer. So, while the
compiler just knows at compile time where the storage (none) for a is
located , it doesn't for a in 2. With 2, whenever a is used, the compiled
program has to dereference the pointer. It does not have to do so with
a, since it does know where the storage for a is.

One has to remark that with 1., the programme has to make sure that there
is enough memory after a for something to be stored. You cannot be sure
if you use automatic or global variables, but in the case of the structs,
you can be (well, almost...)

Another example which might help:

Look at this:

struct {
   char is_byte[0];
   int  is_int;
};

Although this is *not* good programming practice, you can use it to
get each byte of an int (I assume 32 bit ints here).

Assume we have a low-endian machine, then
is_byte[0] is the lowest        byte of is_int
is_byte[1] is the lower-middle  byte of is_int
is_byte[2] is the higher-middle byte of is_int
is_byte[3] is the highest       byte of is_int

This assumes that the fields of the struct are not rearranged, and there
is no padding involved, this is the reason I would call it bad programming
practice. But it works (at least, on most machines/compilers)!

I hope this clarifies a little bit,
   Spiro.

----------------------------------------------------------------------
To unsubscribe from the list send mail to majordomo_at_musoftware.de with
the string "unsubscribe cc65" in the body(!) of the mail.


Date view Thread view Subject view

This archive was generated by hypermail 2.1.3 : 2003-01-23 10:42:12 CET