Howto do the impossible with #define ?>?

A

Ancient_Hacker

It sure would be nice if I could have a macro that add a level of
indirection to its argument.

So if I write: AddIndirection( X )

The macro AddIndirection will do: #define X (*X)

so after that point whenever you use X it gets replaced by (*X)


Now I KNOW you can't have a #define generate another #define, but is
there some sneaky way to do this? Surely the cpp gurus out there can
figure out how?

Thanks,

grg
 
E

Eric Sosman

Ancient_Hacker said:
It sure would be nice if I could have a macro that add a level of
indirection to its argument.

So if I write: AddIndirection( X )

The macro AddIndirection will do: #define X (*X)

so after that point whenever you use X it gets replaced by (*X)

The reason you think this would be "nice" escapes me.
What sort of use would you intend for this bletcherous idea?
Now I KNOW you can't have a #define generate another #define, but is
there some sneaky way to do this? Surely the cpp gurus out there can
figure out how?

Yes, you can do it. But you'll need to spell the
directive a little differently: instead of

AddIndirection(X)

you must write

#define X (*X)

.... and I suspect you will quickly come to regret writing it.
 
A

Ancient_Hacker

Eric Sosman wrote:

The reason you think this would be "nice" escapes me.
What sort of use would you intend for this bletcherous idea?


Did I ask for an opinion as to the nicety of this?

As to the blecherosity of this, it actually has a valid use.

Let's say you're writing a dynamic array library ( for C ). You'd like
the user to be able to write:

MakeMeAnArrayWithFourDimensions( float, MyArray, 10, 20, 30, 40 )

No, you need not comment on my choice of macro names.

One can implement this with:

#define(t,n,d1,d2,d3,d4) \
typedef t n##_Type [d1][d2][d3][d4]; \
typedef n##_Type * n##_Type_Ptr; \
static n##_Type_Ptr n; \
n = (n##_Type_Ptr) malloc( sizeof( n##_Type ) );


No, I don't need your comments about my superflous type definitions and
how clever you could squeeze this down to one line.


Now the only problem is this array MyArray is actually a pointer to
MyArray, so the poor user will have to write (*A) [j][k][q], which
is annoying. Or we could supply yet another macro : #define
Access(n,i,j,k,q) (*n)[j][k][q] but that also is less than
optimum. or we could have created a function: t n(int d1, int d2, int
d3, int d4) {
return * N##_Var[d1][d2][d3][d4] } .... except we'd need a separate
one for returning lvalues.

The only way I can see how to make the use as transparent as possible
is to do a #define MyArray(*MyArray). For those of you that think
this is recursive, it's not, cpp handles this case just fine.


I solicit any clever ideas as to how to do this or similar.

Thanks,

grg
Yes, you can do it. But you'll need to spell the
directive a little differently: instead of

AddIndirection(X)

you must write

#define X (*X)

... and I suspect you will quickly come to regret writing it.


I wonder why you mention this. My original posting clearly indicates
my wish to do this automatically. You somehow feel compelled to beg
the question, plus show an unerring ability to read my mind in the
future. Surely someone of your Godlike powers has better things to do
than quibble on usenet newsgroups?
 
E

Eric Sosman

Ancient_Hacker said:
Did I ask for an opinion as to the nicety of this?

No, you did not ask. You merely stated that "It sure
would be nice," offering no reason why anyone would think
so. I questioned -- and continue to question -- what you
apparently take as an axiom.
As to the blecherosity of this, it actually has a valid use.

Let's say you're writing a dynamic array library ( for C ). You'd like
the user to be able to write:

MakeMeAnArrayWithFourDimensions( float, MyArray, 10, 20, 30, 40 )

No, you need not comment on my choice of macro names.

One can implement this with:

#define(t,n,d1,d2,d3,d4) \
typedef t n##_Type [d1][d2][d3][d4]; \
typedef n##_Type * n##_Type_Ptr; \
static n##_Type_Ptr n; \
n = (n##_Type_Ptr) malloc( sizeof( n##_Type ) );


No, I don't need your comments about my superflous type definitions and
how clever you could squeeze this down to one line.


Now the only problem is this array MyArray is actually a pointer to
MyArray, so the poor user will have to write (*A) [j][k][q], which
is annoying. Or we could supply yet another macro : #define
Access(n,i,j,k,q) (*n)[j][k][q] but that also is less than
optimum. or we could have created a function: t n(int d1, int d2, int
d3, int d4) {
return * N##_Var[d1][d2][d3][d4] } .... except we'd need a separate
one for returning lvalues.

The only way I can see how to make the use as transparent as possible
is to do a #define MyArray(*MyArray). For those of you that think
this is recursive, it's not, cpp handles this case just fine.


Second point first: Of course it isn't recursive; that's the
way the C language is defined.

As for the larger issue, your problem is caused by the wrong
choice of pointer type. Use a pointer to a 3D array to access
your 4D array, and all the problems will disappear. Keep in mind
that C really doesn't have multi-dimensional arrays: it has one-
dimensional arrays whose elements can be one-dimensional arrays,
whose elements can in turn be one-dimensional arrays, ...

When you want to allocate a one-dimensional array of `char',
say, what pointer type do you use? A "zero-dimensional" `char*',
not a one-dimensional `(char[N])*', right? You don't want a pointer
to the array, you want a pointer to the array element -- hence, you
want a pointer with "one less dimension" than the overall array.
I solicit any clever ideas as to how to do this or similar.

If by "this" you mean cause an automatic redefinition, I think
you are out of luck. If by "this" you mean you want to solve the
problem, there's nothing especially "clever" about the straightforward
solution outlined above, but it will work lots better.
I wonder why you mention this. My original posting clearly indicates
my wish to do this automatically. You somehow feel compelled to beg
the question, plus show an unerring ability to read my mind in the
future. Surely someone of your Godlike powers has better things to do
than quibble on usenet newsgroups?

I mention my suspicion to counter your unsupported assertion
that "It sure would be nice." I remain suspicious.
 
K

Kenny McCormack

Ancient_Hacker said:
I wonder why you mention this. My original posting clearly indicates
my wish to do this automatically. You somehow feel compelled to beg
the question, plus show an unerring ability to read my mind in the
future. Surely someone of your Godlike powers has better things to do
than quibble on usenet newsgroups?

Unfortunately, not. That's what's so funny about this group.
You've got all these allegedly high-power, experts-in-their-fields, in
fact, gosh and golly, some of 'em have even claimed to have written (and
gotten published!) actual real live books, yet they don't seem to have
anything better to do with their time than nit-pick strangers here.

Useful clc-related links:

http://en.wikipedia.org/wiki/Clique
http://en.wikipedia.org/wiki/Aspergers
http://en.wikipedia.org/wiki/C_programming_language
 
A

Ancient_Hacker

Eric said:
As for the larger issue, your problem is caused by the wrong
choice of pointer type. Use a pointer to a 3D array to access
your 4D array, and all the problems will disappear.

I should have mentioned, this is in an extremely time_critical app
which already runs for upwards of a week sometimes. We can't afford
the overhead of chasing several pointers
just to get to a data value.

Keep in mind that C really doesn't have multi-dimensional arrays:

It's hard to keep this in mind, especially since IT IS NOT TRUE.

You can declare, in 1973 K&R C: float X[10][20][30]; /* Not A
problem */

What you can't do, at any time between then and now, is pass various
multi-dim arrays as a parameter and expect the receiving function to
index into them correctly. This is something FORTRAN has had since
1959.
it has one-
dimensional arrays whose elements can be one-dimensional arrays,
whose elements can in turn be one-dimensional arrays, ...

yes, many of us are familiar with that kludgy way of faking
"multi-dimensinal arrays". Not interested in paying the price.


Regards,


grg
 
R

Richard Heathfield

Eric Sosman said:

Keep in mind that C really doesn't have multi-dimensional arrays:

I must take issue with you there. C /does/ have multi-dimensional arrays,
because the Standard says it does. 3.3.2.1 and 3.5.7 have plenty of
references to them. (In C99, see 6.5.2.1.)
 
E

Eric Sosman

Ancient_Hacker said:
I should have mentioned, this is in an extremely time_critical app
which already runs for upwards of a week sometimes. We can't afford
the overhead of chasing several pointers
just to get to a data value.

"Chasing several pointers ...?" Oh: You've mis-read
what was written.
It's hard to keep this in mind, especially since IT IS NOT TRUE.

... and the Moon REALLY IS made of green cheese.
You can declare, in 1973 K&R C: float X[10][20][30]; /* Not A
problem */

No, it's not a problem. X is an array of ten things.
each of those -- X[1], for instance -- is an array of twenty
things. Each of those -- e.g. X[1][3] -- is an array of
thirty floats.
What you can't do, at any time between then and now, is pass various
multi-dim arrays as a parameter and expect the receiving function to
index into them correctly. This is something FORTRAN has had since
1959.

"Multi-dimensional" arrays work just fine as parameters,
as long as all but the first dimension are known and constant.
C99 removes the "and constant" part.

As for FORTRAN -- well, if you prefer it, why not use it?
C is certainly not the only language around; it's just the only
one that's topical on this newsgroup.
yes, many of us are familiar with that kludgy way of faking
"multi-dimensinal arrays". Not interested in paying the price.

You didn't read carefully.
 
F

Frederick Gotham

Richard Heathfield posted:
Eric Sosman said:



I must take issue with you there. C /does/ have multi-dimensional arrays,
because the Standard says it does. 3.3.2.1 and 3.5.7 have plenty of
references to them. (In C99, see 6.5.2.1.)


I agree, C certainly does have multi-dimensional arrays.


int (*p_array)[2][4][8][16] =
malloc( sizeof(int) * 2 * 4 * 8 * 16 );

(*p_array)[1][3][7][15] = -78;
p_array[0][1][3][7][15] = -78;
 
R

Richard Heathfield

Ancient_Hacker said:

I should have mentioned, this is in an extremely time_critical app
which already runs for upwards of a week sometimes. We can't afford
the overhead of chasing several pointers
just to get to a data value.

If that's your bottleneck, you're very fortunate. At the risk of being
attacked simply for attempting to help you, I would add that I think your
time would be better spent looking at your algorithm choices, rather than
trying to find a crufty way to hack the preprocessor.

<snip>
 
R

Richard Heathfield

Frederick Gotham said:
Richard Heathfield posted:
Eric Sosman said:



I must take issue with you there. C /does/ have multi-dimensional arrays,
because the Standard says it does. 3.3.2.1 and 3.5.7 have plenty of
references to them. (In C99, see 6.5.2.1.)


I agree, C certainly does have multi-dimensional arrays.


int (*p_array)[2][4][8][16] =
malloc( sizeof(int) * 2 * 4 * 8 * 16 );

More simply:

int (*p_array)[2][4][8][16] = malloc(sizeof *p_array);

if(p_array != NULL)
{
/* THEN you can do this... */
(*p_array)[1][3][7][15] = -78;
p_array[0][1][3][7][15] = -78;
 
E

Eric Sosman

Richard said:
Eric Sosman said:




I must take issue with you there. C /does/ have multi-dimensional arrays,
because the Standard says it does. 3.3.2.1 and 3.5.7 have plenty of
references to them. (In C99, see 6.5.2.1.)

Well, since the Standard uses the term I guess I have to
concede it. IMHO, though, it's a notional convenience that has
snuck into the normative text, sort of like "address" (an idea
C doesn't really need at all).

Note that the description of subscripting in 6.5.2.1/3 is
only one-dimensional; the operation on a "multi-dimensional"
array is described in terms of the decomposition of the MDA
into a singly-dimensioned array of singly-dimensioned arrays
of singly-dimensioned arrays of ... There is a [] operator,
but no [][] operator.

Also, note that the language grammar has no syntax for
declaring an array with multiple dimensions. Rather, it has
syntax for declaring arrays of arrays.

Still, if the Standard says so ... All right, I yield.
 
R

Richard Heathfield

Eric Sosman said:
Well, since the Standard uses the term I guess I have to
concede it. IMHO, though,
[Objections 1 through 4 - snipped]

Still, if the Standard says so ... All right, I yield.

Your objections are very sensible, but you are right to yield. Let us never
forget that sensible != normative. :)
 
E

Eric Sosman

Frederick said:
Richard Heathfield posted:

Eric Sosman said:



I must take issue with you there. C /does/ have multi-dimensional arrays,
because the Standard says it does. 3.3.2.1 and 3.5.7 have plenty of
references to them. (In C99, see 6.5.2.1.)



I agree, C certainly does have multi-dimensional arrays.


int (*p_array)[2][4][8][16] =
malloc( sizeof(int) * 2 * 4 * 8 * 16 );

(*p_array)[1][3][7][15] = -78;
p_array[0][1][3][7][15] = -78;

.... and my suggestion to the O.P. is that he lose the useless
first dimension in the pointer type:

int (*p_array)[4][8][16] =
malloc(sizeof(int) * 2 * 4 * 8 * 16);
/* better: malloc(2 * sizeof *p_array) */
p_array[1][3][7][15] = -78;
 
A

Ancient_Hacker

Eric said:
"Chasing several pointers ...?" Oh: You've mis-read
what was written.

No I havent. It appears you have a very weak idea of what actually has
to happen when you declare an array of array of array of pointers.
Here's a clue:


when you write: x = Array[j][k][q];

AND Array has been declared as the usual kludge, as **** pointers,
the compiler has NO CHOICE but to load up each array index variable,
use it as an index into the array, fetrch the pointer to the next
higher dimension, and repeat that as many times as necessary,.
There's example code from the microsoft C compiler for doing just this:
; 27 : Tot += a_slow_array[j][k];

000c5 8b 45 fc mov eax, DWORD PTR _i$[ebp]
000c8 8b 4d f0 mov ecx, DWORD PTR _a_slow_array$[ebp]
000cb 8b 14 81 mov edx, DWORD PTR [ecx+eax*4]
000ce 8b 45 ec mov eax, DWORD PTR _j$[ebp]
000d1 8b 0c 82 mov ecx, DWORD PTR [edx+eax*4]
000d4 db 45 f8 fild DWORD PTR _Tot$[ebp]
000d7 8b 55 f4 mov edx, DWORD PTR _k$[ebp]
000da d8 04 91 fadd DWORD PTR [ecx+edx*4]
000dd e8 00 00 00 00 call __ftol2_sse
000e2 89 45 f8 mov DWORD PTR _Tot$[ebp], eax
000e5 eb cf jmp SHORT $LN2@wmain
$LN1@wmain:
000e7 eb b5 jmp SHORT $LN5@wmain
$LN4@wmain:
000e9 eb 9b jmp SHORT $LN8@wmain
$LN7@wmain:



You see no optimization is possible, as the compiler has to assume any
value in the pointer array may change at any time. So it has to
generate the really slow code to load up all those pointers. And the
instructions can't be overlapped, as each instruction depends on teh
result of the previous one.

----

But if instead the array is expicitly declared, all the overhead goes
away.
And the compiler can clearly see what index variables are invariant in
the inner loops, so those array subscripts need not be recalculated
each time. And there are fewer temporary registers used, so the code
can be ioptimized even more.. The code is much shorter and faster:

0015b db 45 f8 fild DWORD PTR _Tot$[ebp]
0015e 8b 45 f4 mov eax, DWORD PTR _k$[ebp]
00161 d8 44 81 fc fadd DWORD PTR [ecx+eax*4-4]
... and the Moon REALLY IS made of green cheese.

Are you still in denial?


"Multi-dimensional" arrays work just fine as parameters,
as long as all but the first dimension are known and constant.
C99 removes the "and constant" part.

Read the sentence: Various multi-dimensional arrays. You can't pass:
float X[10][20]
and
float Y[20][30]

to the same routine (say, MatMul). C has no way of conveying the
dimension information, so the called routine has no idea what the
caling array's dimensions are.
You didn't read carefully.

You don't think carefully.
 
A

Ancient_Hacker

Richard said:
If that's your bottleneck, you're very fortunate. At the risk of being
attacked simply for attempting to help you, I would add that I think your
time would be better spent looking at your algorithm choices,

That's usually a swell idea, but the code in question is about 45,000
lines long, already uses lots of optimized matrix libraries, been pored
over by experts for over a decade now.

What would really help is getting these arrays transparently modded
into the code.
 
H

Hallvard B Furuseth

Ancient_Hacker said:
No I havent. It appears you have a very weak idea of what actually
has to happen when you declare an array of array of array of pointers.

Which neither of you have suggested.
Here's a clue:
when you write: x = Array[j][k][q];

AND Array has been declared as the usual kludge, as **** pointers,


Which neither of you have suggested either.
And it is different from an "array of array of array of pointers".
There's example code from the microsoft C compiler for doing just
this:

Indeed. Now have a look at assembly code produced from the code
Eric suggested, instead of the code he didn't suggest.
"Multi-dimensional" arrays work just fine as parameters,
as long as all but the first dimension are known and constant.
C99 removes the "and constant" part.

Read the sentence: Various multi-dimensional arrays. You can't pass:
float X[10][20]
and
float Y[20][30]

Ah, you didn't say that's what you meant until just recently.
You said you wanted macros. I'm as confused as Eric about why
you think those will make a difference. But let's see -

As you yourself say,
"What you can't do, at any time between then and now, is pass various
multi-dim arrays as a parameter and expect the receiving function to
index into them correctly. This is something FORTRAN has had since
1959."
Correct until C99. And any macros you could add would not make a
difference. You'd have to define a one-dimentional arrays and implement
a multi-dim array "by hand" in the function which used it, or something.
(You could use macros to make that easier of course.)

You can pass variable-length arrays to C99 functions, but you need to
tell the function the array lengths as well. E.g.

int foo(int j, int k, int a[*][j][k])
{
return a[1][2][3];
}

which doesn't work in gcc yet, but you could pass a pointer to the
multi-dim array instead or use

int foo(int i, int j, int k, int a[j][k])
{
return a[1][2][3];
}

Also, in C++ you could have declared a function using templates.
 
E

Eric Sosman

Ancient_Hacker said:
Eric Sosman wrote:




No I havent.

"Yes, you have."
It appears you have a very weak idea of what actually has
to happen when you declare an array of array of array of pointers.

You are the introducer of the "array of pointers" idea,
not I. If you will go back and read what I wrote, you will
see that I spoke of a pointer, singular, and of an array of
arrays of arrays of floats. There was no mention, none, zero,
nada, zip, nil, of any array of pointers anywhere in what I
wrote.
Here's a clue:

when you write: x = Array[j][k][q];

AND Array has been declared as the usual kludge, as **** pointers,


It would be clearer to exhibit an actual declaration.
I do not know what you mean by "**** pointers." (I can guess,
but you have left too much room for guesswork and I do not
wish to waste time discussing strawmen. Either write exactly
what you mean, or drop the subject.)
the compiler has NO CHOICE but to load up each array index variable,
use it as an index into the array, fetrch the pointer to the next
higher dimension, and repeat that as many times as necessary,

You are describing an entirely different data structure
from the one I suggested lo! these many flames ago.
Are you still in denial?

No; Richard Heathfield has pointed out my error. You
will note, though, that array subscripting is defined as
one-dimensional, consistent with the "arrays of arrays"
model. "Multi-dimensional array" is officially sanctioned
nomenclature, but carries no meaning beyond "array of arrays."
A multi-dimensional array behaves exactly as I described.
You don't think carefully.

No; I am careless, especially when someone who asks for
help and recieves it responds like North Korea on a bad hair
day.
 
K

Keith Thompson

Eric Sosman said:
Richard said:
Eric Sosman said:

I must take issue with you there. C /does/ have multi-dimensional
arrays, because the Standard says it does. 3.3.2.1 and 3.5.7 have
plenty of references to them. (In C99, see 6.5.2.1.)

Well, since the Standard uses the term I guess I have to
concede it. IMHO, though, it's a notional convenience that has
snuck into the normative text, sort of like "address" (an idea
C doesn't really need at all).

Note that the description of subscripting in 6.5.2.1/3 is
only one-dimensional; the operation on a "multi-dimensional"
array is described in terms of the decomposition of the MDA
into a singly-dimensioned array of singly-dimensioned arrays
of singly-dimensioned arrays of ... There is a [] operator,
but no [][] operator.

Also, note that the language grammar has no syntax for
declaring an array with multiple dimensions. Rather, it has
syntax for declaring arrays of arrays.

Still, if the Standard says so ... All right, I yield.

Some languages have multidimensional arrays as a built-in feature,
distinct from arrays of arrays. C doesn't. It only has arrays,
arrays of arrays, and so forth -- but it uses the term
"multidimensional arrays" to refer to them.

As far as I can tell, C99 6.5.2.1p3, which describes multidimensional
array indexing, is redundant. The rules for indexing into a
multidimensional array follow directly from the rules for indexing
into a one-dimensional array. If that paragraph were removed from the
standard, it wouldn't change the language, except that Eric's
statement that C doesn't have multidimensional arrays, but only arrays
of arrays, would be correct. It's just a matter of terminology.
 
A

Ancient_Hacker

Sorry folks,, I thought we were talking about the very common (if you
Google for "C multi-dimensional dynamic arrays") trick of malloc()ing
an array of pointers to each row, then mallocing an array of pointers
to each of those arrays. Works, but that's about all.

Glad to hear C99 is up to FORTRAN59 level of array handling.
 

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
474,181
Messages
2,570,970
Members
47,537
Latest member
BellCorone

Latest Threads

Top