473,385 Members | 1,356 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

Empty arrays in structs

A question regarding this code, which defines a struct containing a size
and a variable-sized array:

typedef struct
{
uint16_t count;
unsigned char bytes[];
} foo_t;

....

foo_t* foo = (foo_t*)malloc(100 + sizeof(foo_t));

GCC 3.3.2 accepts this, and returns '2' as the result of
'sizeof(foo_t)'. I realize that the size of any struct is
machine/compiler dependent, but can I reasonably expect this code to be
portable? My reading of K&R implies that an array with no size is an
incomplete type, and that you can't take the size of an incomplete type,
and also that structs can't contain objects of incomplete types.
However, I couldn't find anything in the GCC documentation stating that
this was one of their extensions.

If this is not portable, then what is the best way to define a portable
variable-sized array with a header in a contiguous block of memory?
Would I need to just malloc an array, cast the header bytes
appropriately when necessary, and offset everything?

Rennie
Nov 14 '05 #1
7 7481
Rennie deGraaf wrote:
A question regarding this code, which defines a struct containing a size
and a variable-sized array:

typedef struct
{
uint16_t count;
unsigned char bytes[];
} foo_t;

...

foo_t* foo = (foo_t*)malloc(100 + sizeof(foo_t));

GCC 3.3.2 accepts this, and returns '2' as the result of
'sizeof(foo_t)'. I realize that the size of any struct is
machine/compiler dependent, but can I reasonably expect this code to be
portable? My reading of K&R implies that an array with no size is an
incomplete type, and that you can't take the size of an incomplete type,
and also that structs can't contain objects of incomplete types.
However, I couldn't find anything in the GCC documentation stating that
this was one of their extensions.

If this is not portable, then what is the best way to define a portable
variable-sized array with a header in a contiguous block of memory?
Would I need to just malloc an array, cast the header bytes
appropriately when necessary, and offset everything?


It is a C99-ism. See, for example:

http://home.tiscalinet.ch/t_wolf/tw/...es.html#Syntax

at number 28.

HTH,
-ag
--
Artie Gold -- Austin, Texas

http://it-matters.blogspot.com
Nov 14 '05 #2
Artie Gold wrote:
Rennie deGraaf wrote:
A question regarding this code, which defines a struct containing a size
and a variable-sized array:

typedef struct
{
uint16_t count;
unsigned char bytes[];
} foo_t;

...

foo_t* foo = (foo_t*)malloc(100 + sizeof(foo_t));

GCC 3.3.2 accepts this, and returns '2' as the result of
'sizeof(foo_t)'. I realize that the size of any struct is
machine/compiler dependent, but can I reasonably expect this code to be
portable? My reading of K&R implies that an array with no size is an
incomplete type, and that you can't take the size of an incomplete type,
and also that structs can't contain objects of incomplete types.
However, I couldn't find anything in the GCC documentation stating that
this was one of their extensions.
As Artie stated: This is C99. However, variable length arrays
are among the things gcc does not do right (yet), especially
for flexible array members (there is an offsetof issue where
I think the standard has good semantics and is better than the
gcc extension for VLAs but it would break old gnu89 [C89 plus
GNU extensions]).
Have a look at
gcc.gnu.org/c99status.html
In the list at the bottom, you can find a link to a discussion
about flexible array members.

If this is not portable, then what is the best way to define a portable
variable-sized array with a header in a contiguous block of memory?
Would I need to just malloc an array, cast the header bytes
appropriately when necessary, and offset everything?

As for portability: Have a look around whether all compilers
on all intended systems will support a large enough subset of
C99 to make this work. Apart from that: Do not rely on a certain
memory representation of the struct. Another implementation may
introduce different padding and so on. So, "bitwise portability"
is not possible if that is what you have in mind.

It is a C99-ism. See, for example:

http://home.tiscalinet.ch/t_wolf/tw/...es.html#Syntax

at number 28.


In C89 there is also the struct hack to achieve roughly the
same but it is not considered to be conforming.
See FAQ 2.6 at
http://www.eskimo.com/~scs/C-faq/top.html
Note however, that the HTML version of the FAQ is not up to
date; get the ASCII version (linked to from there) to read
the current version.
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #3
On Fri, 26 Nov 2004 05:09:20 UTC, Rennie deGraaf
<ca.ucalgary.cpsc@degraaf> wrote:
A question regarding this code, which defines a struct containing a size
and a variable-sized array:

typedef struct
{
uint16_t count;
unsigned char bytes[];
} foo_t;

...

foo_t* foo = (foo_t*)malloc(100 + sizeof(foo_t));
You are trying to enter the lands of undefined behavior. You should
know that a cast only to get the compiler silent is an error. There is
no need to cast the result of a function that returns pointer to void.
Either you casts garbidge or it would be superflous at all. #include
stdlib.h and you have done anything you need to satisfy the compiler -
and when the compiler gets not satisfyed you knows YOU've done some
mistake - but that mistake will be never a lacking cast.
GCC 3.3.2 accepts this, and returns '2' as the result of
'sizeof(foo_t)'. I realize that the size of any struct is
machine/compiler dependent, but can I reasonably expect this code to be
portable?
No. Its an GCC extension.

My reading of K&R implies that an array with no size is an incomplete type, and that you can't take the size of an incomplete type,
and also that structs can't contain objects of incomplete types.
However, I couldn't find anything in the GCC documentation stating that
this was one of their extensions.
Yes. But ANSI 99/98 allows to create arrays of 0 bytes in size as
placeholder for arrays of variable size.

That means change bytes[] into bytes[0] for ANSI 999/98 or bytes[1]
for ANSI 89.
If this is not portable, then what is the best way to define a portable
variable-sized array with a header in a contiguous block of memory?
Would I need to just malloc an array, cast the header bytes
appropriately when necessary, and offset everything?

Rennie


struct s {
size_t cb; /* optionally, but often helpful */
....
char t[0]; /* ANSI 99/98 OR
char t[1]; ANSI 89 */
};

struct s *ps = malloc(sizeof(struct s) + strlen(my_new_t) + 1);
strcpy(ps->t, my_new_t);
ps->cb = sizeof(struct s) + strlen(my_new_t) + 1;

for ANSI C 89:
struct s {
size_t cb; /* optionally, but often helpful */
....
char t[1]; /* ANSI 99/98 OR
char t[1]; ANSI 89 */
};

struct s *ps = malloc(sizeof(struct s) + strlen(my_new_t));
strcpy(ps->t, my_new_t);
ps->cb = sizeof(struct s) + strlen(my_new_t);
--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
Nov 14 '05 #4
Herbert Rosenau wrote:
On Fri, 26 Nov 2004 05:09:20 UTC, Rennie deGraaf
<ca.ucalgary.cpsc@degraaf> wrote:

A question regarding this code, which defines a struct containing a size
and a variable-sized array:

typedef struct
{
uint16_t count;
unsigned char bytes[];
} foo_t;

...

foo_t* foo = (foo_t*)malloc(100 + sizeof(foo_t));

You are trying to enter the lands of undefined behavior. You should
know that a cast only to get the compiler silent is an error. There is
no need to cast the result of a function that returns pointer to void.
Either you casts garbidge or it would be superflous at all. #include
stdlib.h and you have done anything you need to satisfy the compiler -
and when the compiler gets not satisfyed you knows YOU've done some
mistake - but that mistake will be never a lacking cast.

GCC 3.3.2 accepts this, and returns '2' as the result of
'sizeof(foo_t)'. I realize that the size of any struct is
machine/compiler dependent, but can I reasonably expect this code to be
portable?

No. Its an GCC extension.


Wrong.

My reading of K&R implies that an array with no size is an
incomplete type, and that you can't take the size of an incomplete type,
and also that structs can't contain objects of incomplete types.
However, I couldn't find anything in the GCC documentation stating that
this was one of their extensions.

Yes. But ANSI 99/98 allows to create arrays of 0 bytes in size as
placeholder for arrays of variable size.

That means change bytes[] into bytes[0] for ANSI 999/98 or bytes[1]
for ANSI 89.


Wrong. bytes[] for C99. Have a look at 6.7.2.1, especially at the
example (which is of course not part of the standard but illustrates
the point quickly).
And the C89 struct hack (FAQ 2.6) is _not_ conforming even though
working everywhere.
If this is not portable, then what is the best way to define a portable
variable-sized array with a header in a contiguous block of memory?
Would I need to just malloc an array, cast the header bytes
appropriately when necessary, and offset everything?

Rennie

struct s {
size_t cb; /* optionally, but often helpful */
....
char t[0]; /* ANSI 99/98 OR
char t[1]; ANSI 89 */
};

struct s *ps = malloc(sizeof(struct s) + strlen(my_new_t) + 1);
strcpy(ps->t, my_new_t);
ps->cb = sizeof(struct s) + strlen(my_new_t) + 1;

for ANSI C 89:
struct s {
size_t cb; /* optionally, but often helpful */
....
char t[1]; /* ANSI 99/98 OR
char t[1]; ANSI 89 */
};

struct s *ps = malloc(sizeof(struct s) + strlen(my_new_t));
strcpy(ps->t, my_new_t);
ps->cb = sizeof(struct s) + strlen(my_new_t);


The one thing is wrong, the other plainly non-conforming.
-Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #5
> struct s {
size_t cb; /* optionally, but often helpful */
....
char t[0]; /* ANSI 99/98 OR
char t[1]; ANSI 89 */
};

struct s *ps = malloc(sizeof(struct s) + strlen(my_new_t) + 1);
strcpy(ps->t, my_new_t);
ps->cb = sizeof(struct s) + strlen(my_new_t) + 1;

for ANSI C 89:
struct s {
size_t cb; /* optionally, but often helpful */
....
char t[1]; /* ANSI 99/98 OR
char t[1]; ANSI 89 */
};

struct s *ps = malloc(sizeof(struct s) + strlen(my_new_t));
strcpy(ps->t, my_new_t);
ps->cb = sizeof(struct s) + strlen(my_new_t);


Is this code safe? I can see the purpose behind it, but I think accessing an
array beyond its bounds (regardless if there is allocated space to do so)
may cause problems. Can someone confirm or deny this?
Nov 14 '05 #6
On Fri, 26 Nov 2004 10:35:54 UTC, "Method Man" <a@b.c> wrote:
struct s {
size_t cb; /* optionally, but often helpful */
....
char t[0]; /* ANSI 99/98 OR
char t[1]; ANSI 89 */
};

struct s *ps = malloc(sizeof(struct s) + strlen(my_new_t) + 1);
strcpy(ps->t, my_new_t);
ps->cb = sizeof(struct s) + strlen(my_new_t) + 1;

for ANSI C 89:
struct s {
size_t cb; /* optionally, but often helpful */
....
char t[1]; /* ANSI 99/98 OR
char t[1]; ANSI 89 */
};

struct s *ps = malloc(sizeof(struct s) + strlen(my_new_t));
strcpy(ps->t, my_new_t);
ps->cb = sizeof(struct s) + strlen(my_new_t);


Is this code safe? I can see the purpose behind it, but I think accessing an
array beyond its bounds (regardless if there is allocated space to do so)
may cause problems. Can someone confirm or deny this?


It would NOT work for static created structs!

so

struct s;
struct s[4711];

will NOT work as expected. Get memory dynamically using the malloc()
family or OS dependand memory allocation and you gets what you asks
for. C knows nothing about bounds checking - if you use a bounds
checker on your system it may cry - or may not.

--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
Nov 14 '05 #7
In article <6G******************@read1.cgocable.net>,
Method Man <a@b.c> wrote:
struct s {
size_t cb; /* optionally, but often helpful */
....
char t[0]; /* ANSI 99/98 OR
char t[1]; ANSI 89 */
};

struct s *ps = malloc(sizeof(struct s) + strlen(my_new_t) + 1);
strcpy(ps->t, my_new_t);
ps->cb = sizeof(struct s) + strlen(my_new_t) + 1;

for ANSI C 89:
struct s {
size_t cb; /* optionally, but often helpful */
....
char t[1]; /* ANSI 99/98 OR
char t[1]; ANSI 89 */
};

struct s *ps = malloc(sizeof(struct s) + strlen(my_new_t));
strcpy(ps->t, my_new_t);
ps->cb = sizeof(struct s) + strlen(my_new_t);
Is this code safe? I can see the purpose behind it, but I think accessing an
array beyond its bounds (regardless if there is allocated space to do so)
may cause problems. Can someone confirm or deny this?


Officially in C89 accessing a array beyond its bounds causes undefined
behaviour, but it works on all C compilers I have seen. In C99 they added
the variable length field to make this defined behaviour.

I try to avoid this, but I have used it occasionally where memory was
extremely tight.

Kevin.

Nov 14 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Dave A | last post by:
The following C code specifies the interface into a DLL. I need to access it from C#. How do I do declare it? I have done simple ones before but this particular API requires a pointer to a struct...
19
by: Canonical Latin | last post by:
"Leor Zolman" <leor@bdsoft.com> wrote > "Canonical Latin" <javaplus@hotmail.com> wrote: > > > ... > >But I'm still curious as to the rational of having type >...
21
by: Matteo Settenvini | last post by:
Ok, I'm quite a newbie, so this question may appear silly. I'm using g++ 3.3.x. I had been taught that an array isn't a lot different from a pointer (in fact you can use the pointer arithmetics to...
5
by: Gomaw Beoyr | last post by:
Hello Is there any explanation why Microsoft chose to implement arrays as objects allocated on the heap instead of structs allocated on the stack? For "mathematical stuff", one normally...
33
by: Peter Seaman | last post by:
I understand that structures are value types and arrays and classes are reference types. But what about arrays as members of structures i.e. as in C struct x { int n; int a; }
3
by: Michel Rouzic | last post by:
It's the first time I try using structs, and I'm getting confused with it and can't make it work properly I firstly define the structure by this : typedef struct { char *l1; int *l2; int Nval; }...
10
by: David Fort | last post by:
Hi, I'm upgrading a VB6 app to VB.net and I'm having a problem with a call to a function provided in a DLL. The function takes the address of a structure which it will fill in with values. I...
3
by: Zenon | last post by:
I have a function which returns array of structs. I need to create a collection of those arrays and thought that an ArrayList would be a good way to do this since the count is variable. The...
127
by: sanjay.vasudevan | last post by:
Why are the following declarations invalid in C? int f(); int f(); It would be great if anyone could also explain the design decision for such a language restricton. Regards, Sanjay
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.