473,465 Members | 1,524 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Preprocessor fun; \xdigits



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
Nov 13 '05 #1
7 1692

On Thu, 13 Nov 2003, Arthur J. O'Dwyer wrote:

static const int *bucket_sizes = (const int *)
"\x01\x00\x00\x00"
"\x02\x00\x00\x00"
[...] 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

Wouldn't you know it, as soon as I posted that, I went
back to the source I was struggling with and produced
the following [half-tested]:

#define G(X) #X
#define F(X,Y) G(X ## Y)
#define E(X) F(\x, X)
#define ARRAY_ELEM(w,x,y,z) E(z) E(y) E(x) E(w)
#define BEGIN_ARRAY(foo) static const int *foo = (const int *)
#define END_ARRAY ;

Just to check: That's all legal C90, right?
Or is gcc hiding something from me again?
Better ideas still welcomed,
-Arthur
Nov 13 '05 #2
"Arthur J. O'Dwyer" <aj*@nospam.andrew.cmu.edu> writes:
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
};
[...]
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?


Following is untested, uncompiled, and poorly proofread:

static size_t *bucket_sizes;
static size_t n_buckets, m_buckets;

static void add_bucket (size_t value)
{
if (n_buckets >= m_buckets) {
m_buckets = (m_buckets + 8) * 3 / 2;
bucket_sizes = realloc (bucket_sizes,
sizeof *bucket_sizes * m_buckets);
}
bucket_sizes[n_buckets++] = value;
}

static void init_buckets (void)
{
size_t size;

for (size = 1; size < 32; size++)
add_bucket (size);

for (size = 32; size < 1024; size *= 2) {
add_bucket (size);
add_bucket (size * 3 / 2);
}

/* I *think* this is correct. Caveat programmer. */
for (size = 1024; size >= 1024; size *= 2)
add_bucket (size);

add_bucket (-1);
}
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}
Nov 13 '05 #3
"Arthur J. O'Dwyer" <aj*@nospam.andrew.cmu.edu> writes:
Wouldn't you know it, as soon as I posted that, I went
back to the source I was struggling with and produced
the following [half-tested]:

#define G(X) #X
#define F(X,Y) G(X ## Y)
#define E(X) F(\x, X)
#define ARRAY_ELEM(w,x,y,z) E(z) E(y) E(x) E(w)
#define BEGIN_ARRAY(foo) static const int *foo = (const int *)
#define END_ARRAY ;


You're planning to turn this in as part of a class? Or as part
of an International Obfuscated C Coding Contest entry?
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}
Nov 13 '05 #4

On Thu, 13 Nov 2003, Ben Pfaff wrote:

"Arthur J. O'Dwyer" <aj*@nospam.andrew.cmu.edu> writes:

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
};
[...]


<snip most of Ben's very nice code>
for (size = 1; size < 32; size++)
add_bucket (size);

for (size = 32; size < 1024; size *= 2) {
add_bucket (size);
add_bucket (size * 3 / 2);
}


Sorry, Ben, I wasn't as clear as I could've been.
The bucket sizes aren't as nicely fixed as all
that; they're meant to be listed out in a neat
little [hah!] array whose elements can be looked
at and modified by the maintainer (that's me).
I already wrote a little tool that looks at
what size blocks are being requested by the test
suite and give me a neat listing of the sizes I
should be using for best performance. [It tells
me, for instance, that I don't need a bucket for
"5", but I do need a bucket for "4072".]

Thanks for taking the time to look at it, though.
And re your other post: Yes, for a class. No,
not for the IOCCC -- it's not *nearly* obfuscated
enough. Heck, it's about as clear as I can make
it, within the rules! :-)
Now the relevant portion of the code looks
like this (comments show macro substitution
results):

BEGIN(segr_size) /* size_t *segr_size = (size_t*) */
HEX_ELEM(00,02) /* "\x02\x00\x00\x00" */
HEX_ELEM(00,03) /* "\x03\x00\x00\x00" */
[...]
HEX_ELEM(15,DA) /* "\xDA\x15\x00\x00" */
LAST_ELEM /* "\xFF\xFF\xFF\xFF" */
END(segr_size); /* ; */

I don't suppose anyone has any clever ways of
computing the length of the string pointed to by
'segr_size' as an integer constant expression,
do they? ;-)

Thanks,
-Arthur
Nov 13 '05 #5
"Arthur J. O'Dwyer" <aj*@nospam.andrew.cmu.edu> writes:
On Thu, 13 Nov 2003, Ben Pfaff wrote:

<snip most of Ben's very nice code>
for (size = 1; size < 32; size++)
add_bucket (size);

for (size = 32; size < 1024; size *= 2) {
add_bucket (size);
add_bucket (size * 3 / 2);
}


Sorry, Ben, I wasn't as clear as I could've been.
The bucket sizes aren't as nicely fixed as all
that; they're meant to be listed out in a neat
little [hah!] array whose elements can be looked
at and modified by the maintainer (that's me).


Something like this then?

#include <stddef.h>
#include <stdarg.h>

void add_buckets (unsigned long first, ...)
{
va_list args;

if (first == -1)
return;
add_bucket (first);

va_start (args, first);
for (;;) {
unsigned long next = va_arg (args, unsigned long);
if (next == -1)
break;
add_bucket (next);
}
va_end (args);
}

....
add_buckets (1ul, 2ul, 3ul, ..., -1ul);
....

--
"I don't have C&V for that handy, but I've got Dan Pop."
--E. Gibbons
Nov 13 '05 #6
Arthur J. O'Dwyer wrote:
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.]


What about:

int get_bucket_size(int i)
{
const size_t bucket_sizes[] = {
1, 2, 3, 4, 5, [...],
32, 48, 64, 96, 128, [...],
1024, 2048, 4096, [...],
(size_t)-1
};
return bucket_sizes[i];
}

?/MG

Nov 13 '05 #7
In article
<Pi***********************************@unix49.andr ew.cmu.edu>,
"Arthur J. O'Dwyer" <aj*@nospam.andrew.cmu.edu> wrote:
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?


It is your task to find a solution that demonstrates good programming
practices, while at the same time formally obeying the given
restrictions and demonstrating their stupidity.

Write your code using static structs as you would normally do it.
Restrict yourself to reading and writing struct members, on +=, -=
operators etc. Test the code until it is working. Since this is
something that you _are_ supposed to learn, there will be no help with
this.

Start a new file. Should look like

#ifdef GOOD_SOLUTION
<original code>
#else
<stupid code>
#endif

The <stupid code> is initially your original code. Then you change it
step by step to obey the rules. Define two macros

#structget(dst,type,name,member) dst = name.member
#structput(type,name,member,src) name.member = src

If you had a static struct

static struct xstruct x;

and an assignment x.y = z;

then replace this with

structput (struct xstruct, x, y, z);

If you had an access like

z = x.y;

the replace this with

structget (z, struct xstruct, x, y);

Test until your code is working. Now you are ready to please the grading
robot: Replace each static struct with a char* of the same name.
Allocate enough memory for each at initialisation time. Then replace the
get/put macros:

#define structget(dst,type,name,member) \
do { type dummy; memcpy (&dummy, name, sizeof type); \
dst = dummy.member; } while (0)

#define structput(type,name,member,src) \
do { type dummy; memcpy (&dummy, name, sizeof type); \
dummy.member = src; memcpy (name, &dummy, sizeof type); \
} while (0)

To make sure that your grading robot has no valid excuses to grade you
down, change things slightly:

#ifdef GOOD_SOLUTION
<original code>
#else
<struct declarations>
#if EFFICIENT_CODE
static struct xstruct x;
...
#define structget... (first version)
#else
static unsigned char* x;
...
#define structput... (second version)
#endif
#endif
Nov 13 '05 #8

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

Similar topics

205
by: Jeremy Siek | last post by:
CALL FOR PAPERS/PARTICIPATION C++, Boost, and the Future of C++ Libraries Workshop at OOPSLA October 24-28, 2004 Vancouver, British Columbia, Canada http://tinyurl.com/4n5pf Submissions
24
by: Nudge | last post by:
I have an array, and an unrolled loop which looks like this: do_something(A); do_something(A); .... do_something(A); I thought: why should I type so much? I should write a macro. So I was...
16
by: Trying_Harder | last post by:
Is it possible to redefine a macro with global scope after undefining it in a function? If yes, could someone explain how? /If/ my question above isn't very clear you can refer to the...
18
by: /* frank */ | last post by:
My teacher said that array in C is managed by preprocessor. Preprocesser replace all array occurences (i.e. int a ) with something that I don't understand/remember well. What's exactly happens...
13
by: Chris Croughton | last post by:
Is the following code standard-compliant, and if so what should it do? And where in the standard defines the behaviour? #include <stdio.h> #define DEF defined XXX int main(void) { int...
9
by: Walter Roberson | last post by:
I have run into a peculiarity with SGI's C compiler (7.3.1.2m). I have been reading carefully over the ANSI X3.159-1989 specification, but I cannot seem to find a justification for the behaviour....
32
by: spibou | last post by:
Is the output of the C preprocessor deterministic ? What I mean by that is , given 2 compilers which conform to the same standard, will their preprocessors produce identical output given as input...
31
by: Sam of California | last post by:
Is it accurate to say that "the preprocessor is just a pass in the parsing of the source file"? I responded to that comment by saying that the preprocessor is not just a pass. It processes...
6
by: Subra | last post by:
Hi, Compilation of the below code fails #define a this1, /* Comma is intentional line 1*/ #define fun( x, y, z) y*x*z/*line 2*/ char this1,b,c;/*line 3*/
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
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...

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.