A
Arthur J. O'Dwyer
Okay, here's a useless and contrived challenge for
those here who know the preprocessor better than I
do.
Introduction: For a school project, we must <ot>build
a malloc package for a Linux system.</ot> It has to
satisfy several bizarre constraints in order to make the
grading robot happy, including the following:
No named objects of non-scalar type and static storage
duration. I.e., no static arrays, no structs at file
scope, etc., etc. [My paraphrase of the real constraint,
which is of course more vaguely specified. But that's
the gist of it.]
Naturally, I want to have a global array something like
the following:
static const size_t bucket_sizes[] = {
1, 2, 3, 4, 5, [...],
32, 48, 64, 96, 128, [...],
1024, 2048, 4096, [...],
(size_t)-1
};
for use with a segregated-storage-type malloc package.
(The array holds the sizes of storage available to the
system, and we keep linked lists of blocks of those
sizes, blah blah blah...)
But I can't do that, because it would violate the
rules of the robot. Yes, I've asked the TA, and yes,
really we can't have global arrays.
So the design issue is: How best to handle the initialization
of an "array," without actually making it a real C array?
Obviously, I could write
static int *bucket_sizes = NULL;
[...]
bucket_sizes = get_some_memory(LOTS);
bucket_sizes[0] = 1;
bucket_sizes[1] = 2;
bucket_sizes[2] = 3;
[...]
....but that's just ridiculously ugly and bad.
So I thought I might be able to keep the nice array
structure by using the following *VERY UNPORTABLE*
method:
static const int *bucket_sizes = (const int *)
"\x01\x00\x00\x00"
"\x02\x00\x00\x00"
"\x03\x00\x00\x00"
[...]
"\x00\x04\x00\x00"
"\x00\x08\x00\x00"
"\x00\x10\x00\x00"
[...]
"\xFF\xFF\xFF\xFF"
;
Now, this is still ugly, but it is allowed by the
TA (yes, I checked, honestly it is!), and it looks
to me like it *should* be easy to come up with a
system of macros so that I could easily write:
BEGIN_ARRAY(bucket_sizes)
ARRAY_ELEM(00,00,00,01)
ARRAY_ELEM(00,00,00,02)
ARRAY_ELEM(00,00,00,03)
ARRAY_ELEM(00,00,04,00)
ARRAY_ELEM(00,00,08,00)
ARRAY_ELEM(00,00,10,00)
ARRAY_ELEM(FF,FF,FF,FF)
END_ARRAY
and somehow get that string representation out of
the macros. But I can't figure out if there's any
way to insert the necessary \x's in front of each
hex digit pair and still trick the compiler into
thinking it's one token.
Can anyone help with this?
Or show that it can't be done the way I want?
Or (even better) give a "better" alternative
that still obeys the robot's rules about global
data structures?
Thanks much,
-Arthur
those here who know the preprocessor better than I
do.
Introduction: For a school project, we must <ot>build
a malloc package for a Linux system.</ot> It has to
satisfy several bizarre constraints in order to make the
grading robot happy, including the following:
No named objects of non-scalar type and static storage
duration. I.e., no static arrays, no structs at file
scope, etc., etc. [My paraphrase of the real constraint,
which is of course more vaguely specified. But that's
the gist of it.]
Naturally, I want to have a global array something like
the following:
static const size_t bucket_sizes[] = {
1, 2, 3, 4, 5, [...],
32, 48, 64, 96, 128, [...],
1024, 2048, 4096, [...],
(size_t)-1
};
for use with a segregated-storage-type malloc package.
(The array holds the sizes of storage available to the
system, and we keep linked lists of blocks of those
sizes, blah blah blah...)
But I can't do that, because it would violate the
rules of the robot. Yes, I've asked the TA, and yes,
really we can't have global arrays.
So the design issue is: How best to handle the initialization
of an "array," without actually making it a real C array?
Obviously, I could write
static int *bucket_sizes = NULL;
[...]
bucket_sizes = get_some_memory(LOTS);
bucket_sizes[0] = 1;
bucket_sizes[1] = 2;
bucket_sizes[2] = 3;
[...]
....but that's just ridiculously ugly and bad.
So I thought I might be able to keep the nice array
structure by using the following *VERY UNPORTABLE*
method:
static const int *bucket_sizes = (const int *)
"\x01\x00\x00\x00"
"\x02\x00\x00\x00"
"\x03\x00\x00\x00"
[...]
"\x00\x04\x00\x00"
"\x00\x08\x00\x00"
"\x00\x10\x00\x00"
[...]
"\xFF\xFF\xFF\xFF"
;
Now, this is still ugly, but it is allowed by the
TA (yes, I checked, honestly it is!), and it looks
to me like it *should* be easy to come up with a
system of macros so that I could easily write:
BEGIN_ARRAY(bucket_sizes)
ARRAY_ELEM(00,00,00,01)
ARRAY_ELEM(00,00,00,02)
ARRAY_ELEM(00,00,00,03)
ARRAY_ELEM(00,00,04,00)
ARRAY_ELEM(00,00,08,00)
ARRAY_ELEM(00,00,10,00)
ARRAY_ELEM(FF,FF,FF,FF)
END_ARRAY
and somehow get that string representation out of
the macros. But I can't figure out if there's any
way to insert the necessary \x's in front of each
hex digit pair and still trick the compiler into
thinking it's one token.
Can anyone help with this?
Or show that it can't be done the way I want?
Or (even better) give a "better" alternative
that still obeys the robot's rules about global
data structures?
Thanks much,
-Arthur