471,585 Members | 1,478 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

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

What does the array do?

Recently I have come across a number of struct's that I think is quite
interesting:

typedef struct whatever_tag
{
int member1;
char member2;
// ...

char last_member[1]; // interesting line
} whatever;

My quetions is, why an array of size 1 instead of just a single object?
It looks like C code instead of C++ though, hope it's not off-topic.

Ben
Feb 12 '06 #1
11 1764
* benben:
Recently I have come across a number of struct's that I think is quite
interesting:

typedef struct whatever_tag
{
int member1;
char member2;
// ...

char last_member[1]; // interesting line
} whatever;

My quetions is, why an array of size 1 instead of just a single object?
It looks like C code instead of C++ though, hope it's not off-topic.


It is indeed C code. The idea is to do something like

whatever* w = malloc( offsetof( whatever, last_member ) + n_items ) );
w->last_member[n_items-1] = something;

In C++ make last_member a std::vector, for example.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Feb 12 '06 #2
benben wrote:
Recently I have come across a number of struct's that I think is quite
interesting:

typedef struct whatever_tag
{
int member1;
char member2;
// ...

char last_member[1]; // interesting line
} whatever;

My quetions is, why an array of size 1 instead of just a single
object? It looks like C code instead of C++ though, hope it's not
off-topic.


It is often better to ask in comp.lang.c about any C construct.

In good old times, to create a structure with "dynamic" part you would
declare an array of 1, like above, then allocate (using 'malloc') more
than (sizeof(whatever)) by a certain number of bytes. Once allocated,
such structure would be considered to contain an array of 'certain number
of bytes' at its end, and not an array of 1. Since indexing is not part
of array semantics, but instead a pointer thing, you could write:

whatever *pw = (whatever*) malloc(sizeof(whatever) + 150);
pw->last_member[100] = 42;

and it would be OK.

This practice has been essentially replaced by several techniques in C++.
You can have a template with a template-argument-sized array, you can
have a class that dynamically allocates part of it, etc.

The advantage of using this old C trick is that the memory for that
array is right there, essentially _in_ the object (convenient for the
purposes of, say, serialization). The disadvantage is that you have
to store the size of the object in the object.

V
--
Please remove capital As from my address when replying by mail
Feb 12 '06 #3
* Victor Bazarov, doing C:

whatever *pw = (whatever*) malloc(sizeof(whatever) + 150);


In C, casting the result of malloc is Evil. One reason is that if the
relevant #include for malloc has been omitted, the cast may do Very
Unholy Things, where the malloc result pointer is converted to an int
which is in turn converted to a typed pointer, with no diagnostic. In
C++ we have stronger typing and hence in C++ the cast should be there,
if for any reason we'd choose to use C malloc instead of C++ new.

Cheers,

- ALf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Feb 12 '06 #4
> The advantage of using this old C trick is that the memory for that
array is right there, essentially _in_ the object (convenient for the
purposes of, say, serialization). The disadvantage is that you have
to store the size of the object in the object.

V


Thank you for the reply!

If I am not too far off I guess with this trick only the first element
in the array can be properly destroyed if it has a destructor?

Ben
Feb 12 '06 #5
On Sun, 12 Feb 2006 02:04:07 +0100, "Alf P. Steinbach"
<al***@start.no> wrote:
* Victor Bazarov, doing C:

whatever *pw = (whatever*) malloc(sizeof(whatever) + 150);


In C, casting the result of malloc is Evil. One reason is that if the
relevant #include for malloc has been omitted, the cast may do Very
Unholy Things, where the malloc result pointer is converted to an int
which is in turn converted to a typed pointer, with no diagnostic.


Interesting point of view. AFAIK, ANSI-C requires a prototyp for a
function, otherwise it should not compile. Moreover, the return value
of malloc is a void* and it's usually considered good style to use an
explicit cast when you cast from void* and not rely on the implicit
cast (that is possible in C).

Regards,
Roland Pibinger
Feb 12 '06 #6
* Roland Pibinger:
On Sun, 12 Feb 2006 02:04:07 +0100, "Alf P. Steinbach"
<al***@start.no> wrote:
* Victor Bazarov, doing C:
whatever *pw = (whatever*) malloc(sizeof(whatever) + 150); In C, casting the result of malloc is Evil. One reason is that if the
relevant #include for malloc has been omitted, the cast may do Very
Unholy Things, where the malloc result pointer is converted to an int
which is in turn converted to a typed pointer, with no diagnostic.


Interesting point of view.


Well, it's a FAQ (C FAQ item 7.7b) -- so perhaps it's interesting! ;-)
See <url: http://c-faq.com/malloc/mallocnocast.html>.

AFAIK, ANSI-C requires a prototyp for a
function, otherwise it should not compile.
Nope. It may be so in C99. But according to <url:
http://www.cpax.org.uk/prg/writings/casting.php> (I'm just throwing in a
typical web page discussing this, other than the C FAQ) section 3.3.2.2
of the ANSI C Standard of 1989 states:

<quote>
If the expression that precedes the parenthesized argument list
in a function call consists solely of an identifier, and if no
declaration is visible for this identifier, the identifier is
implicitly declared exactly as if, in the innermost block
containing the function call, the declaration

extern int identifier();

appeared.
</quote>

Moreover, the return value of malloc is a void*
Nope, not if you don't have a declaration; then it's an int (see above).

and it's usually considered good style to use an
explicit cast when you cast from void* and not rely on the implicit
cast (that is possible in C).


Nope.

Cheers, and hope this helps,

- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Feb 12 '06 #7

"benben" <be******@yahoo.com.au> skrev i meddelandet
news:43**********************@news.optusnet.com.au ...
The advantage of using this old C trick is that the memory for that
array is right there, essentially _in_ the object (convenient for
the
purposes of, say, serialization). The disadvantage is that you
have
to store the size of the object in the object.

V


Thank you for the reply!

If I am not too far off I guess with this trick only the first
element in the array can be properly destroyed if it has a
destructor?


It's a C thing, so it doesn't have a destructor. :-)
If you put non-POD C++ objects in the struct, you open a whole new can
of worms.

Please don't do that! :-)
Bo Persson
Feb 12 '06 #8
Roland Pibinger wrote:
On Sun, 12 Feb 2006 02:04:07 +0100, "Alf P. Steinbach"
<al***@start.no> wrote:
* Victor Bazarov, doing C:

whatever *pw = (whatever*) malloc(sizeof(whatever) + 150);


In C, casting the result of malloc is Evil. One reason is that if
the relevant #include for malloc has been omitted, the cast may do
Very Unholy Things, where the malloc result pointer is converted to
an int which is in turn converted to a typed pointer, with no
diagnostic.


Interesting point of view. AFAIK, ANSI-C requires a prototyp for a
function, otherwise it should not compile. Moreover, the return value
of malloc is a void* and it's usually considered good style to use an
explicit cast when you cast from void* and not rely on the implicit
cast (that is possible in C).


As Alf says in his follow-up, the prototype requirement didn't come
into play until C99. Prior to that, implicit declarations were
possible. As to your second contention, it is the general consensus on
comp.lang.c that it is BAD style to use unnecessary casts, especially
when such casts may hide serious programming errors. Covering up a
mismatch between declaration and implementation is generally considered
a serious problem.

Brian

Feb 12 '06 #9
On Sun, 12 Feb 2006 13:03:33 +0100, "Alf P. Steinbach"
<al***@start.no> wrote:
according to <url:
http://www.cpax.org.uk/prg/writings/casting.php> (I'm just throwing in a
typical web page discussing this, other than the C FAQ) section 3.3.2.2
of the ANSI C Standard of 1989 states:

<quote>
If the expression that precedes the parenthesized argument list
in a function call consists solely of an identifier, and if no
declaration is visible for this identifier, the identifier is
implicitly declared exactly as if, in the innermost block
containing the function call, the declaration

extern int identifier();

appeared.
</quote>


You are right. K&R use prototypes permanently and emphasize their
importance several times in the book. Hence the false impression. But
C-Compilers usually issue a warning for undeclared functions.

Regards,
Roland Pibinger
Feb 12 '06 #10

"benben" <be******@yahoo.com.au> wrote in message
news:43***********************@news.optusnet.com.a u...
Recently I have come across a number of struct's that I think is quite
interesting:

typedef struct whatever_tag
{
int member1;
char member2;
// ...

char last_member[1]; // interesting line
} whatever;

My quetions is, why an array of size 1 instead of just a single object?
It looks like C code instead of C++ though, hope it's not off-topic.

Ben


As some of the other posting have explained, the array is so that you can
tag on a
dynamic piece of memory to the basic structure. However, I think the [1] is
slightly incorrect,
typically this should be [0]. If the intent of the structure is what we have
assumed, you'd
be wasting one char on each structure (unless some special logic has been
used to allocate
a malloc'd array one char too small and similar convoluted logic has been
used to access
the array). Might be because some compilers will detect you are indexing
into a zero
sized array ?
Feb 12 '06 #11
* Dave Townsend:
* benben:
Recently I have come across a number of struct's that I think is quite
interesting:

typedef struct whatever_tag
{
int member1;
char member2;
// ...

char last_member[1]; // interesting line
} whatever;

My quetions is, why an array of size 1 instead of just a single object?
It looks like C code instead of C++ though, hope it's not off-topic.


As some of the other posting have explained, the array is so that you can
tag on a dynamic piece of memory to the basic structure. However, I think
the [1] is slightly incorrect, typically this should be [0].


In C++ an array size of 0 is invalid, and requires a diagnostic from the
compiler. Before the template way like BOOST_STATIC_ASSERT using arrays
size 0 to implement a kind of static assert was not unusual. I don't
know whether an array size of 0 is valid in C, or not.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Feb 13 '06 #12

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by F. Da Costa | last post: by
140 posts views Thread by Oliver Brausch | last post: by
6 posts views Thread by Niklaus | last post: by
18 posts views Thread by Matt | last post: by
13 posts views Thread by Jason Huang | last post: by
14 posts views Thread by Bit byte | last post: by
5 posts views Thread by Cylix | last post: by
reply views Thread by XIAOLAOHU | last post: by
reply views Thread by leo001 | last post: by
reply views Thread by Anwar ali | last post: by

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.