How to construct preprocessed functions

B

Bey

I want to write preprocessor functions/arrays that are evaluated at
compile time. For example, if I define

#define MYARR[] {5,4,3,2,1,0}

then, the code

int x = R[0];

should be presented as

int x = 5;

to the compiler. (of course only literals can be used in the index).
This is important if code size/memory is critical and we dont want to
store MYARR, but we need it for coding convenience.

Compile time functions would also be good. For example, something like

#define MYMAP(n)
#if n==1
5
#else
2

So, the statement
int x = MYMAP(4);
should be presented to the compiler as
int x = 2;

Obviously, we have to use a literal as the argument. Is this possible?

Thanks!
 
C

Chïna Blüe Öyster Cult

Bey said:
#define MYARR[] {5,4,3,2,1,0}

then, the code

int x = R[0];

You can try
#include <stdio.h>
#define N 6
#define R ((int[N]){5,4,2,3,1,0})

int main(int argc, char **argv) {
int i; for (i=0; i<N; i++) printf("%d. %d\n", i, R);
return 0;
}
and see if constant folding simplifies it for you.
Compile time functions would also be good. For example, something like

#define MYMAP(n)
#if n==1
5
#else
2

m5 is widely available and can do this.
 
S

Seebs

I want to write preprocessor functions/arrays that are evaluated at
compile time.

Basically, you can't.

But wait. Why do you want to?

Are you even sure you actually want to?
This is important if code size/memory is critical and we dont want to
store MYARR, but we need it for coding convenience.

Suggest you use a reasonably good modern compiler. They will generally
do pretty well at figuring this stuff out.
Compile time functions would also be good. For example, something like

#define MYMAP(n)
#if n==1
5
#else
2

So, the statement
int x = MYMAP(4);
should be presented to the compiler as
int x = 2;

Obviously, we have to use a literal as the argument. Is this possible?

Basically, no.

But.

If you have a reasonably simple function, and declare it static inline,
and call it with an argument which may or may not be literal, you will
likely discover that a good compiler silently eliminates all the processing
in the cases where you used a literal, because the output is completely
determined at compile time.

Before you spend a lot of time and effort on this, I urge you to actually
find out what your compiler is generating now, and what it generates at
different optimization levels. Your task may already be done.

-s
 
G

Gene

I want to write preprocessor functions/arrays that are evaluated at
compile time. For example, if I define

#define MYARR[] {5,4,3,2,1,0}

then, the code

int x = R[0];

should be presented as

int x = 5;

to the compiler. (of course only literals can be used in the index).
This is important if code size/memory is critical and we dont want to
store MYARR, but we need it for coding convenience.

Compile time functions would also be good. For example, something like

#define MYMAP(n)
#if n==1
5
#else
2

So, the statement
int x = MYMAP(4);
should be presented to the compiler as
int x = 2;

Obviously, we have to use a literal as the argument. Is this possible?

Thanks!

Pretty much no. I take it you are trying to implement some kind of
table lookup at compile time.

In C89, the best you can do is probably this:

#define R0 5
#define R1 4
#define R2 3
#define R3 2
#define R4 1
#define R5 0

#define EXPAND(X) X
#define R(I) EXPAND(R ## I)

int x = R(0);

#define MAP(X) ((X) == 1 ? 5 : 2)

int x = MAP(4);

$ gcc -E zoo.c
[ some lines deleted ]
int x = 5;
int x = ((4) == 1 ? 5 : 2);

The second is really no problem. Just about any compiler will fold
the ternary to a constant.

As has been mentioned, in C99 you can create a foldable constant array
expression for the first case as well.
 
E

Eric Sosman

I want to write preprocessor functions/arrays that are evaluated at
compile time. For example, if I define

#define MYARR[] {5,4,3,2,1,0}

then, the code

int x = R[0];

should be presented as

int x = 5;

to the compiler. (of course only literals can be used in the index).

As shown, that can't work: `{5,4,3,2,1,0}' is a valid initializer
list for an array of int, but also for a lot of other things, some of
which aren't even arrays. You need a type somewhere, and there's no
type in sight.

(Of course, the example you offer could be coded without recourse
to any fancy footwork: Assuming R and MYARR are supposed to be the
same, `#define R(x) (5-(x))' would work pretty well. But I'll suppose
you're interested in outcomes that are less easily predicted.)
This is important if code size/memory is critical and we dont want to
store MYARR, but we need it for coding convenience.

You may be pursuing the root of all evil here, but if you're dead-
set on being clever in the teeth of the evidence:

enum {MYARR0=5,MYARR1=4,MYARR2=3,MYARR3=2,MYARR4=1,MYARR5=0};
#define R(x) RHELPER(x)
#define RHELPER(x) MYARR ## x
int x = R(0); // note () instead of []

(Caution: I don't use token-pasting all that much, and when I do I
always consult the book. My book isn't handy at the moment and I
can't check, so all I can do is say "Bang the rocks together, guys!"
and assure you that there's a way to turn MYARR 2 into MYARR2 -- a
way that is left as an exercise to the student.)
Compile time functions would also be good. For example, something like

#define MYMAP(n)
#if n==1
5
#else
2

No good: The expansion of a macro *never* produces a preprocessor
directive, not even if it produces a token sequence that resembles one.
That is, a macro cannot expand to an #if..#else..#endif sequence, not
no way, not no how.

Still, there's `#define MYMAP(n) ((n) == 1 ? 5 : 2)' and variants
thereof. Since you seem not to have considered such things, I suppose
that you haven't studied what's actually going on in your code -- which
leads us back once again to the root of all evil.
So, the statement
int x = MYMAP(4);
should be presented to the compiler as
int x = 2;

Obviously, we have to use a literal as the argument. Is this possible?

"Nobody cares."

In other words: *First* demonstrate, by actual measurement, that
you have a problem. *Then* you may get someone interested in helping
you solve it -- but very few people will be strongly motivated to help
fight the monsters that live under your bed at night.
 
B

Bey

You can try
    #include <stdio.h>
    #define N 6
    #define R ((int[N]){5,4,2,3,1,0})

    int main(int argc, char **argv) {
        int i; for (i=0; i<N; i++) printf("%d. %d\n", i, R);
        return 0;
    }
and see if constant folding simplifies it for you.
Compile time functions would also be good. For example, something like
#define MYMAP(n)
#if n==1
5
#else
2

m5 is widely available and can do this.

Thanks! Could you give me a reference on m5?
 
K

Keith Thompson

Chïna Blüe Öyster Cult said:
m5 is widely available and can do this.

Do you mean m4? A quick Google search indicates that there is at
least one macro processor called "m5", but m4 is much more common
(it's preinstalled on most Unix-like systems and there's a GNU
implementation).
 
C

Chïna Blüe Öyster Cult

[QUOTE="Keith Thompson said:
m5 is widely available and can do this.

Do you mean m4? A quick Google search indicates that there is at[/QUOTE]

--m5
 
L

luserXtrog

I want to write preprocessor functions/arrays that are evaluated at
compile time. For example, if I define

#define MYARR[] {5,4,3,2,1,0}

then, the code

int x = R[0];

should be presented as

int x = 5;

to the compiler. (of course only literals can be used in the index).
This is important if code size/memory is critical and we dont want to
store MYARR, but we need it for coding convenience.

Compile time functions would also be good. For example, something like

#define MYMAP(n)
#if n==1
5
#else
2

So, the statement
int x = MYMAP(4);
should be presented to the compiler as
int x = 2;

Obviously, we have to use a literal as the argument. Is this possible?


Depending upon how many hoops you'd like to go through,
then maybe. But you may not be thrilled when you see it.
The following will work only with 6 elements.


/* need extra level to force extra eval */
#define Paste(a,b) a ## b
#define XPASTE(a,b) Paste(a,b)

#define AR0(a,b,c,d,e,f) a
#define AR1(a,b,c,d,e,f) b
#define AR2(a,b,c,d,e,f) c
#define AR3(a,b,c,d,e,f) d
#define AR4(a,b,c,d,e,f) e
#define AR5(a,b,c,d,e,f) f
#define AR_(M, ...) M(__VA_ARGS__)
#define AR(n, ...) AR_(XPASTE(AR, n), __VA_ARGS__)
#define R(n) AR(n,MYARR)

/*
#define MYARR[] {5,4,3,2,1,0}
then, the code
int x = R[0];
should be presented as
int x = 5;
*/

#define MYARR 5,4,3,2,1,0

int x = R(0);

/* gcc -E produces:
# 1 "cpparr.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "cpparr.c"
# 56 "cpparr.c"
int x = 5;

*/
 
L

luserXtrog

<a senile ancestor to the following buffoonery>

Earlier restrictions lifted.



/* need extra level to force extra eval */
#define Paste(a,b) a ## b
#define XPASTE(a,b) Paste(a,b)

#define AR0(a, ...) a
#define AR1(a,b, ...) b
#define AR2(a,b,c, ...) c
#define AR3(a,b,c,d, ...) d
#define AR4(a,b,c,d,e, ...) e
#define AR5(a,b,c,d,e,f, ...) f
#define AR6(a,b,c,d,e,f,g, ...) g
#define AR7(a,b,c,d,e,f,g,h, ...) h
#define AR8(a,b,c,d,e,f,g,h,i, ...) i
#define AR_(M, ...) M(__VA_ARGS__)
#define AR(n, ...) AR_(XPASTE(AR, n), __VA_ARGS__)
#define R(n) AR(n,MYARR)

#define MYARR 5,4,3,2,1,0

int x = R(0);

#undef MYARR
#define MYARR 1,2,3,4,5,6,7,8

int y = R(3);

/* gcc -E produces:
# 1 "cpparr.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "cpparr.c"
# 21 "cpparr.c"
int x = 5;

int y = 4;

*/
 
S

Shao Miller

Bey said:
I want to write preprocessor functions/arrays that are evaluated at
compile time. For example, if I define

#define MYARR[] {5,4,3,2,1,0}

I think that you might be stuck with with '()' rather than '[]' in your
'#define'.
then, the code

int x = R[0];

should be presented as

int x = 5;

Did you mean 'int x = MYARR[0];' above? Also, would you be willing to
use 'MYARR(0)', instead?

Here's something that doesn't actually expand to '5', but I believe
expands to an "integer constant expression"[1], and so might be useful
to you:

#include <stdio.h>

#define MY_ARR_(X, Y) \
X(Y, 0, 5) \
X(Y, 1, 4) \
X(Y, 2, 3) \
X(Y, 3, 2) \
X(Y, 4, 1) \
X(Y, 5, 0)

#define INDEX_MATCH(A, B, C) (A == B) ? C :
#define MY_ARR(A) (MY_ARR_(INDEX_MATCH, A) (0/0))

int main(void) {
int x = MY_ARR(0);

printf("MY_ARR(0) yielded: %d\n", x);
return 0;
}
to the compiler. (of course only literals can be used in the index).
This is important if code size/memory is critical and we dont want to
store MYARR, but we need it for coding convenience.

Compile time functions would also be good. For example, something like

#define MYMAP(n)
#if n==1
5
#else
2

This seems like it could be very similar to your former request. Other
folks have mentioned that a macro cannot expand to preprocessor
directives. That doesn't mean that you can't get something pretty which
has some desired result(s).
So, the statement
int x = MYMAP(4);
should be presented to the compiler as
int x = 2;

Obviously, we have to use a literal as the argument. Is this possible?

I think that there might be reasonably pleasant alternatives.

[1] C99 draft with filename 'n1256.pdf', section 6.6, paragraph *gulp* 6.
 
S

Shao Miller

Shao said:
... ... ...

#define MY_ARR_(X, Y) \
X(Y, 0, 5) \
X(Y, 1, 4) \
X(Y, 2, 3) \
X(Y, 3, 2) \
X(Y, 4, 1) \
X(Y, 5, 0)

#define INDEX_MATCH(A, B, C) (A == B) ? C :
#define MY_ARR(A) (MY_ARR_(INDEX_MATCH, A) (0/0))

... ... ...

Actually, some extra "protection" might be nice. For fun, the 'Y' in
each line of 'MY_ARR_' can remain "unprotected", perhaps because
'MY_ARR_' is best used only in the definitions of macros themselves,
which warrant careful attention.

#define INDEX_MATCH(A, B, C) ((A) == (B)) ? (C) :
#define MY_ARR(A) (MY_ARR_(INDEX_MATCH, (A)) (0/0))
 
L

luserXtrog

One more revision.
Now's it's nicely OCD formatted.


#define AR0(a, ...) a
#define AR1(a,b, ...) b
#define AR2(a,b,c, ...) c
#define AR3(a,b,c,d, ...) d
#define AR4(a,b,c,d,e, ...) e
#define AR5(a,b,c,d,e,f, ...) f
#define AR6(a,b,c,d,e,f,g, ...) g
#define AR7(a,b,c,d,e,f,g,h, ...) h
#define AR8(a,b,c,d,e,f,g,h,i, ...) i
#define AR9(a,b,c,d,e,f,g,h,i,j, ...) j
#define AR10(a,b,c,d,e,f,g,h,i,j,k, ...) k
#define AR11(a,b,c,d,e,f,g,h,i,j,k,l, ...) l
#define AR12(a,b,c,d,e,f,g,h,i,j,k,l,m, ...) m
#define AR13(a,b,c,d,e,f,g,h,i,j,k,l,m,n, ...) n
#define AR14(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o, ...) o
#define AR15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p, ...) p
#define AR16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q, ...) q
#define AR(n, ...) AR_(XPASTE(AR, n), __VA_ARGS__)
#define AR_(M, ...) M(__VA_ARGS__)
#define XPASTE(a,b) Paste(a,b)
#define Paste(a,b) a ## b

#define R(n) AR(n, 5,4,3,2,1,0 )
int x = R(0);

#define S(n) AR(n, 1,2,3,4,5,6,7,8,9,10,11,12 )
int y = S(10);

#define T(n) AR(n, "this","that","both","other" )
char *z = T(2);

#define U(n) AR(n, R(3),S(2),T(1) )
intptr_t w = U(2);

/* gcc -E produces:
# 1 "cpparr.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "cpparr.c"
# 25 "cpparr.c"
int x = 5;


int y = 11;


char *z = "both";


intptr_t w = "that";
*/
 
W

Walter Banks

Seebs said:
But wait. Why do you want to?

One case I can think of is in the evaluation of math functions that
are implemented as the sum of a series . One of the more compact
ways of defining the constants is in an array and macros can be
written to create a math statement to evaluate the function. There is
no need to keep the array around and no need to do an array access
to do the evaluation.

Regards,


walter..
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,113
Latest member
Vinay KumarNevatia
Top