| |
 |
|
| Computers Forum Index » Computer Architecture - Embedded » Squeezing bytes out of a struct... |
|
Page 1 of 1 |
|
| Author |
Message |
| D Yuniskis... |
Posted: Mon Oct 26, 2009 11:12 pm |
|
|
|
Guest
|
Hi,
[I'll post this here instead of c.l.c as I suspect folks here
are far more adept at "squeezing bytes" out of things (vs.
the "desktop jocks")]
While arguably not legitimate, the following is in the
*spirit* of the language (consider much of this pseudo-code):
typedef struct {
size_t length;
int foo;
char bar;
element_t array;
} fussbucket_t;
fussbucket_t sample;
sample.array[0] = (element_t) foo;
sample.array[1] = (element_t) bar;
ASSERT(sample.array == sample.array[0]);
etc.
To accommodate cases where sizeof(array) is "too large"
(whatever that means) to dangle off the bussbucket_t,
you could optionally store a pointer to the array in
place of array[0]. E.g.,
typedef struct {
size_t length;
int foo;
char bar;
union {
element_t array;
element_t *pointer;
} u;
} fussbucket_t;
fussbucket_t sample;
element_t longArray[A_BIG_NUMBER];
sample.u.array[0] = &longArray[0];
If sizeof(element_t) is smaller than sizeof(element_t *),
then you can cheat and pack a few element_t's into the
union. I.e., as if:
struct {
size_t length;
int foo;
char bar;
union {
element_t array[sizeof(element_t *)/sizeof(element_t)];
element_t *pointer;
} u;
}
I *think* this may be portable -- I haven't even checked the
syntax to see if I've shot myself in the foot before I even got
started! :< Is there a cleaner way of doing this? I can
already see some pathological cases where it would *look* right
and yet result in entities that would choke at run-time.
Thx!
--don |
|
|
| Back to top |
|
|
|
| D Yuniskis... |
Posted: Mon Oct 26, 2009 11:45 pm |
|
|
|
Guest
|
D Yuniskis wrote:
[Grrr... should probably have run this through cc before posting :< ]
Quote: typedef struct {
size_t length;
int foo;
char bar;
element_t array;
} fussbucket_t;
fussbucket_t sample;
sample.array[0] = (element_t) foo;
sample.array[1] = (element_t) bar;
sample.array[0] = (element_t) fu;
sample.array[1] = (element_t) baz;
(eliminate any confusion with struct members)
Quote: To accommodate cases where sizeof(array) is "too large"
(whatever that means) to dangle off the bussbucket_t,
s/bussbucket_t/fussbucket_t/
Quote: typedef struct {
size_t length;
int foo;
char bar;
union {
element_t array;
element_t *pointer;
} u;
} fussbucket_t;
fussbucket_t sample;
element_t longArray[A_BIG_NUMBER];
sample.u.array[0] = &longArray[0];
sample.u.pointer = &longArray[0];
[sorry!] |
|
|
| Back to top |
|
|
|
| David Brown... |
Posted: Tue Oct 27, 2009 12:45 am |
|
|
|
Guest
|
D Yuniskis wrote:
Quote: Hi,
[I'll post this here instead of c.l.c as I suspect folks here
are far more adept at "squeezing bytes" out of things (vs.
the "desktop jocks")]
It's probably fair to say that the c.l.c. crowd are more concerned with
what is theoretically correct in C, while in c.a.e. we are more
concerned with practical working code.
Quote: While arguably not legitimate, the following is in the
*spirit* of the language (consider much of this pseudo-code):
Your code is inarguably not legitimate, and is not in the "spirit" of
any language I know of.
It would help enormously if you could give a short description of what
you are trying to do - it's very hard to guess from this post. Your
second "correction" post doesn't really help either - it is still
mangled code, and mixing in partial quotations from your first post with
partial corrections and smart-ass "sed" notation makes it even less clear.
Figure out what you are trying to do, and explain it in a post. Then
someone will probably be able to help you.
mvh.,
David |
|
|
| Back to top |
|
|
|
| Jon Kirwan... |
Posted: Tue Oct 27, 2009 1:22 am |
|
|
|
Guest
|
On Mon, 26 Oct 2009 21:45:07 +0100, David Brown
<david.brown at (no spam) hesbynett.removethisbit.no> wrote:
Quote: D Yuniskis wrote:
Hi,
[I'll post this here instead of c.l.c as I suspect folks here
are far more adept at "squeezing bytes" out of things (vs.
the "desktop jocks")]
It's probably fair to say that the c.l.c. crowd are more concerned with
what is theoretically correct in C, while in c.a.e. we are more
concerned with practical working code.
While arguably not legitimate, the following is in the
*spirit* of the language (consider much of this pseudo-code):
Your code is inarguably not legitimate, and is not in the "spirit" of
any language I know of.
It would help enormously if you could give a short description of what
you are trying to do - it's very hard to guess from this post. Your
second "correction" post doesn't really help either - it is still
mangled code, and mixing in partial quotations from your first post with
partial corrections and smart-ass "sed" notation makes it even less clear.
Figure out what you are trying to do, and explain it in a post. Then
someone will probably be able to help you.
mvh.,
The best I could make of it is that the op wanted something like:
typedef struct {
size_t length;
int foo;
char bar;
element_t array[1];
} fussbucket_t;
And then use:
fussbucket_t* sample= (fussbucket_t *) malloc(
sizeof( fussbucket_t )+
sizeof( element_t ) * (n-1)
);
sample->length = n;
sample->array[0] = (element_t) foo;
sample->array[1] = (element_t) bar;
.
.
up to some limit determined by sample->length.
But I think that is standard c and discussed in the standard.
So that left me more certain I don't understand.
Oh, well.
Jon |
|
|
| Back to top |
|
|
|
| Chris Burrows... |
Posted: Tue Oct 27, 2009 1:44 am |
|
|
|
Guest
|
"David Brown" <david.brown at (no spam) hesbynett.removethisbit.no> wrote in message
news:eqGdnY3Ij-DLl3vXnZ2dnUVZ8s6dnZ2d at (no spam) lyse.net...
Quote:
It's probably fair to say that the c.l.c. crowd are more concerned with
what is theoretically correct in C, while in c.a.e. we are more concerned
with practical working code.
Agreed. Not only working but also maintainable. The sample code posted was
anything but that.
--
Chris Burrows
CFB Software
http://www.cfbsoftware.com |
|
|
| Back to top |
|
|
|
| Thad Smith... |
Posted: Tue Oct 27, 2009 5:15 am |
|
|
|
Guest
|
D Yuniskis wrote:
Quote: Hi,
[I'll post this here instead of c.l.c as I suspect folks here
are far more adept at "squeezing bytes" out of things (vs.
the "desktop jocks")]
While arguably not legitimate, the following is in the
*spirit* of the language (consider much of this pseudo-code):
typedef struct {
size_t length;
int foo;
char bar;
element_t array;
} fussbucket_t;
fussbucket_t sample;
sample.array[0] = (element_t) foo;
sample.array[1] = (element_t) bar;
You can only index array types and pointer types. What is the type of
element_t?
Quote: ASSERT(sample.array == sample.array[0]);
That is true if array is a multidimensional array, but not, in general,
otherwise.
Quote: To accommodate cases where sizeof(array) is "too large"
(whatever that means) to dangle off the bussbucket_t,
you could optionally store a pointer to the array in
place of array[0]. E.g.,
typedef struct {
size_t length;
int foo;
char bar;
union {
element_t array;
element_t *pointer;
} u;
} fussbucket_t;
fussbucket_t sample;
element_t longArray[A_BIG_NUMBER];
sample.u.array[0] = &longArray[0];
If sizeof(element_t) is smaller than sizeof(element_t *),
then you can cheat and pack a few element_t's into the
union. I.e., as if:
struct {
size_t length;
int foo;
char bar;
union {
element_t array[sizeof(element_t *)/sizeof(element_t)];
element_t *pointer;
} u;
}
I *think* this may be portable -- I haven't even checked the
syntax to see if I've shot myself in the foot before I even got
started!
That works if sizeof(element_t*) >= sizeof(element_t). Of course, that
is true only for small types. In the general case, if that is not true,
you have declared an array of zero elements, which isn't allowed in that
part of the declaration.
You could make it work by using a max() macro:
element_t
array[max(sizeof(element_t),sizeof(element_t*))/sizeof(element_t)];
which guarantees at least one item in array. Unfortunately, you cannot
use the standard preprocessor for selecting different code, depending on
which is greater.
--
Thad |
|
|
| Back to top |
|
|
|
| D Yuniskis... |
Posted: Tue Oct 27, 2009 8:21 pm |
|
|
|
Guest
|
[I've merged in some of the corrections I posted earlier
but have refrained from making all syntactic changes]
Thad Smith wrote:
Quote: D Yuniskis wrote:
typedef struct {
size_t length;
int fu;
char baz;
element_t array;
} fussbucket_t;
fussbucket_t sample;
sample.array[0] = (element_t) foo;
sample.array[1] = (element_t) bar;
You can only index array types and pointer types. What is the type of
element_t?
Yes, this was intended just to illustrate dangling the
balance of the "array" off the end of the struct. See the
later example for better syntax...
Quote: ASSERT(sample.array == sample.array[0]);
That is true if array is a multidimensional array, but not, in general,
otherwise.
Again, it is intended to state that the 0th element of
the array resides within the struct. How else could I
express it (array[0] == array[0] is too obvious :> )
Quote: To accommodate cases where sizeof(array) is "too large"
(whatever that means) to dangle off the bussbucket_t,
you could optionally store a pointer to the array in
place of array[0]. E.g.,
typedef struct {
size_t length;
int fu;
char baz;
union {
element_t array;
element_t *pointer;
} u;
} fussbucket_t;
fussbucket_t sample;
element_t longArray[A_BIG_NUMBER];
sample.u.array[0] = &longArray[0];
If sizeof(element_t) is smaller than sizeof(element_t *),
then you can cheat and pack a few element_t's into the
union. I.e., as if:
struct {
size_t length;
int fu;
char baz;
union {
element_t array[sizeof(element_t *)/sizeof(element_t)];
element_t *pointer;
} u;
}
I *think* this may be portable -- I haven't even checked the
syntax to see if I've shot myself in the foot before I even got
started!
That works if sizeof(element_t*) >= sizeof(element_t).
Yes, as I said:
"If sizeof(element_t) is smaller than sizeof(element_t *), ..."
it also works if sizeof(element_t *) == sizeof(element_t) but
that degenerates to the original example.
Quote: Of course, that is true only for small types.
Exactly. If element_t is "big" (relatively speaking), then
there are no economies in this approach. But, in *practice*,
this lets me pack as many as eight in.
Aside from the syntactic complexity, there is no real
cost to this approach (though on some older compilers
the extra addressing could benefit from a good peephole
optimizer).
On more modern platforms, there was an unexpected and notable
performance *benefit* (besides space economies). I
suspect this may be a side-effect of references to the
struct's members priming the cache (exploiting locality
of reference between the "element_t's" and the other
struct members that are associated with them).
Quote: In the general case, if that is not true,
you have declared an array of zero elements, which isn't allowed
in that part of the declaration.
The risk only happens when sizeof(element_t) > sizeof(element_t *).
This is something that the developer has to safeguard against
as there is no way that I can "#error" at compile time. What
I have done is added a tiny executable to my makefile that
essentially compares the sizeof's, prints an error message
and returns a nonzero result code that causes the make(1) to
fail with the message that it displays.
I can think of no other way to enforce this requirement.
Quote: You could make it work by using a max() macro:
element_t
array[max(sizeof(element_t),sizeof(element_t*))/sizeof(element_t)];
This is only legal in newer C (C99?). E.g.,
you couldn't put such a declaration in file scope... (?)
Quote: which guarantees at least one item in array. Unfortunately, you cannot
use the standard preprocessor for selecting different code, depending on
which is greater.
Exactly. An unfortunate consequence of sizeof not being valid
in the preprocessor (though I have found many compilers that
*will* recognize its use there).
There is also a hazard that can bite a sloppy coder if
sizeof(element_t *) mod sizeof(element_t) != 0. But,
you can't protect against incompetence (I guess
I could provide a macro to simplify accessing the array
elements while avoiding this hazard). |
|
|
| Back to top |
|
|
|
| D Yuniskis... |
Posted: Tue Oct 27, 2009 8:26 pm |
|
|
|
Guest
|
Chris Burrows wrote:
Quote: Agreed. Not only working but also maintainable. The sample code posted was
anything but that.
Perhaps you could suggest how this could be made *more*
maintainable? (keeping in mind that you don't want to
make it *brittle* in the process!)
The following should compile and "work". I can't imagine
how to change it to make it more "maintainable" :-(
=====================================
typedef struct {
size_t length;
int fu;
char baz;
union {
element_t *pointer;
element_t array[sizeof(element_t *)/sizeof(element_t)];
} u;
} fussbucket_t;
#define FREEBIES (sizeof(element_t *)/sizeof(element_t))
int main(int argc, char *argv[])
{
fussbucket_t fuss, *fptr;
element_t elem, longArray[(CNT)];
int count;
ASSERT((CNT) > 0);
ASSERT((NUM) >= 0);
ASSERT(sizeof(element_t *) >= sizeof(element_t)); /* FREEBIES > 0 */
/* trivial case */
fuss.u.array[0] = elem; /* guaranteed to fit */
/* optimization */
for (count = 0; count < (FREEBIES); count++) {
fuss.u.array[count] = elem; /* guaranteed to fit */
}
/* dangling elements */
fptr = (fussbucket_t *)
malloc(sizeof(fussbucket_t) + ((NUM) * sizeof(element_t)));
ASSERT(fptr != NULL);
for (count = 0; count < (FREEBIES) + (NUM); count++) {
fptr->u.array[count] = elem; /* guaranteed to fit */
}
free(fptr);
/* external storage */
fuss.u.pointer = &longArray[0];
for (count = 0; count < (CNT); count++) {
*fuss.u.pointer++ = elem; /* guaranteed to fit */
}
return 0;
} |
|
|
| Back to top |
|
|
|
| Mike Paff... |
Posted: Tue Oct 27, 2009 9:23 pm |
|
|
|
Guest
|
On Tue, 27 Oct 2009 09:26:07 -0700, D Yuniskis
<not.going.to.be at (no spam) seen.com> wrote:
Quote: Chris Burrows wrote:
Agreed. Not only working but also maintainable. The sample code posted was
anything but that.
Perhaps you could suggest how this could be made *more*
maintainable? (keeping in mind that you don't want to
make it *brittle* in the process!)
The following should compile and "work". I can't imagine
how to change it to make it more "maintainable" :-(
A big thing that makes code maintainable is good comments.
Describe what each variable/structure/type is used for.
Describe input & output parameters. Include a description of
each function/procedure's purpose, assumptions, and limitations. |
|
|
| Back to top |
|
|
|
| David Brown... |
Posted: Wed Oct 28, 2009 1:32 am |
|
|
|
Guest
|
D Yuniskis wrote:
Quote: [I've merged in some of the corrections I posted earlier
but have refrained from making all syntactic changes]
Thad Smith wrote:
D Yuniskis wrote:
snip
The risk only happens when sizeof(element_t) > sizeof(element_t *).
This is something that the developer has to safeguard against
as there is no way that I can "#error" at compile time. What
I have done is added a tiny executable to my makefile that
essentially compares the sizeof's, prints an error message
and returns a nonzero result code that causes the make(1) to
fail with the message that it displays.
I can think of no other way to enforce this requirement.
You can't do this directly with an #error (though C++ 0x should include
static asserts, and it will probably turn up in C compilers too).
However, you can "cheat" to get static asserts by using declarations
like this:
extern char sizeCheck[
(int) sizeof(element_t *) - (int) sizeof(element_t)];
If sizeof(element_t) is greater than of a pointer, this is a declaration
of an extern array of negative size, giving a compile-time error.
(Without the (int), this would be calculated with unsigned arithmetic
and just declare a very big array.)
Quote: You could make it work by using a max() macro:
element_t
array[max(sizeof(element_t),sizeof(element_t*))/sizeof(element_t)];
This is only legal in newer C (C99?). E.g.,
you couldn't put such a declaration in file scope... (?)
I believe that with a "standard" max macro, it is legal for pretty much
any C.
#define max(a, b) (((a) > (b)) ? (a) : (b))
Quote: which guarantees at least one item in array. Unfortunately, you
cannot use the standard preprocessor for selecting different code,
depending on which is greater.
Exactly. An unfortunate consequence of sizeof not being valid
in the preprocessor (though I have found many compilers that
*will* recognize its use there).
There is also a hazard that can bite a sloppy coder if
sizeof(element_t *) mod sizeof(element_t) != 0. But,
you can't protect against incompetence  (I guess
I could provide a macro to simplify accessing the array
elements while avoiding this hazard).
extern char modCheck[!(sizeof(element_t *) % sizeof(element_t)) - 1]; |
|
|
| Back to top |
|
|
|
| Chris Burrows... |
Posted: Wed Oct 28, 2009 2:36 am |
|
|
|
Guest
|
"D Yuniskis" <not.going.to.be at (no spam) seen.com> wrote in message
news:hc76jv$n5q$1 at (no spam) aioe.org...
Quote: Chris Burrows wrote:
Agreed. Not only working but also maintainable. The sample code posted
was anything but that.
Perhaps you could suggest how this could be made *more*
maintainable? (keeping in mind that you don't want to
make it *brittle* in the process!)
Some more information is required first. AFAICS you have proposed a solution
without clearly describing the problem domain that it is attempting to
address.
What exactly are you trying to achieve?
What alternative solutions have you rejected and why?
Have some particular real-world circumstances driven you to devise such an
obscure approach or is this just an intellectual exercise?
--
Chris Burrows
CFB Software
Armaide: ARM Integrated Development System
http://www.cfbsoftware.com/armaide |
|
|
| Back to top |
|
|
|
| Jon Kirwan... |
Posted: Wed Oct 28, 2009 3:56 am |
|
|
|
Guest
|
On Wed, 28 Oct 2009 08:54:18 +1030, "Chris Burrows"
<cfbsoftware at (no spam) hotmail.com> wrote:
Quote: "D Yuniskis" <not.going.to.be at (no spam) seen.com> wrote in message
news:hc76jv$n5q$1 at (no spam) aioe.org...
Chris Burrows wrote:
Agreed. Not only working but also maintainable. The sample code posted
was anything but that.
Perhaps you could suggest how this could be made *more*
maintainable? (keeping in mind that you don't want to
make it *brittle* in the process!)
Some more information is required first. AFAICS you have proposed a solution
without clearly describing the problem domain that it is attempting to
address.
What exactly are you trying to achieve?
What alternative solutions have you rejected and why?
Have some particular real-world circumstances driven you to devise such an
obscure approach or is this just an intellectual exercise?
I was just about to ask the same thing.
Jon |
|
|
| Back to top |
|
|
|
|
|
All times are GMT
The time now is Mon Nov 23, 2009 5:15 pm
|
|