Array as pointer and explicit pointer

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi All,

I had a slight hiccup in my code, which was easily solved, but now I've got the time to revisit it, I can't work out whether it should have been a problem in the first place or not...

Here, I define two structs:

struct text_array	{
	unsigned int	number;
	unsigned char	text[];
	} TEXT_ARRAYS[] = 
	{
	{ 0x0000, "AABBCCDDEEFF" },
	{ 0x0101, "GGHHIIJJKKLL" },
	{ 0xAA55, "MMNNOOPPQQRR" }
	};
/* End Struct */

struct text_pointer	{
	unsigned int	number;
	unsigned char	*text;
	} TEXT_POINTERS[] = 
	{
	{ 0x1235, "AABBCCDDEEFF" },
	{ 0x2463, "GGHHIIJJKKLL" },
	{ 0xABED, "MMNNOOPPQQRR" }
	};
/* End Struct */

Initially I thought they should produce identical code, but it seems that gcc struggles with a dynamic array defined at the end of the struct. The second struct accesses all elements ok, but the first struct is treated differently and produces code that compiles okay, but cannot access anything correctly.

Is it me? (It usually is!) Or should the first instance still work the same as the second?

I have attached a small project directory to enable testing in AVRStudio, and compilation, etc...

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If the first instance could possibly work at all, it would certainly produce different code than the second. Consider the struct

struct text_pointer {
   unsigned int number;
   unsigned char *text;
};

This struct is always 4 bytes long, consisting of a number and a pointer.

struct text_pointer TEXT_POINTERS[] = {
   {0x1235, "AABBCCDDEEFF"},
   {0x2463, "GGHHIIJJKKLL"}
};

Work from the inside out. First, it creates two unnamed string literals -- "AABBCCDDEEFF" and "GGHHIIJJKKLL". They exist at some arbitrary location in RAM.

Next, it creates an array of two structs. Each struct consists of 4 bytes: a 2-byte number, and a 2-byte pointer. The pointers point to the two unnamed string literals.

This is implemented as 8 contiguous bytes of storage for the array of structs itself, plus two 13-byte spaces (in arbitrary locations) for the two unnamed literals.

Next, consider this code:

struct text_array {
   unsigned int number;
   unsigned char text[];
};

This defines a struct of unspecified length, consisting of a byte, and space for a string inline within the struct's own storage space.

If you run a sizeof(struct text_array), you get 2. That is, the compiler assumes that the ".text" member is a zero-length string. aka, it doesn't exist.

In practice, such a struct could be used in conjunction with malloc() to dynamically allocate space for a variable-length string at run-time, but, instead of malloc(sizeof(struct text_array)), you'd do malloc(sizeof(int) + num_char).

I don't think such a struct is useful for compile-time variable allocation.

An array of struct text_array's will have sizeof(struct text_array) bytes per entry (2 bytes), and in memory you will just see the ".number" members lined up in succession. The storage space for the ".text" member will immediately follow that for the ".number" member. However, since the ".text" member is assumed to have zero length, its address will be equal to the address of the ".number" member of the next entry.

If you modified the text struct to have a fixed, non-zero, embedded string length, then things will start working the way you want:

struct text_array {
   unsigned int number;
   unsigned char text[13];
};

struct text_array TEXT_ARRAYS[] = {
   {0x0000, "AABBCCDDEEFF"},
   {0x0101, "GGHHIIJJKKLL"}
};
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

Thanks for the thorough response, although it still doesn't make entire sense to me to be honest. If this was not a struct, there would be no problem in identifying - text[] = "Some random Text";

Using text would get us a word sized char pointer to S, yet placing this in a struct seems different, or an exception. I suppose it's just because it's written as an array of structures rather than single structures that could be called by their variable names.

I cannot see how text[] get's assumed to be zero bytes either, surely by definition it should allocate 2-bytes as a pointer to the first character in the string, even if the array is treated such that this text field will only be a single char in length.

Unfortunately the text fields are different lengths, so I can't set a specifier for the string length. The explicit pointer has worked a treat, I just wondered why the text[] specification wouldn't work.

Many Thanks,

Brian.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You seem to regard pointers and arrays as the same thing. This is not true and they are very different when you consider the memory layout of structures containing them.
Also, I would almost expect a warning from gcc for the construct in your first example but it seems you have to add "-pedantic" on the command line to get that:

Quote:

main.c:21: warning: invalid use of structure with flexible array member

You can read about zero length arrays here:
http://gcc.gnu.org/onlinedocs/gcc-3.4.3/gcc/Zero-Length.html#Zero-Length
/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for that info Lars, I may turn on pedantic, as you never know what I may have done considering I am still learning so much about C.

Thanks for the link, the next bit of that doc - varaible length arrays gives me the sentence that makes me understand...

Quote:
The storage is allocated at the point of declaration and deallocated when the brace-level is exited

So it would be impossible, because how I thought it would work is to only store the array address here, but that is only the case if it's declared as a pointer.

Clearly I need to read the chapter on pointers and arrays in Kernighan and ritchie's book again!