Really Weird Conversation

M

Mr. Berserker

I was posting stuff to a mailing list when a friend, Prof. Corbessero
and I came up with this one. Perhaps you can help resolve this, or add
anything else worth knowing?? Maybe it should be added to the FAQ for
further reference... :)
Ahh. This is my area... C stores arrays in a form called "column
major" order, which actually means the rows come first (don't ask!).
So, here is what a 3x4 array looks like in memory

-------------------------------------------------------------------------
| 0,0 | 0,1 | 0,2 | 0,3 | 1,0 | 1,1 | 1,2 | 1,3 | 2,0 | 2,1 | 2,2 | 2,3 |
-------------------------------------------------------------------------

When you pass an array to a function, all that is really passed is the
address of the first element. With the above layout in mind, as long
as the function knows how long the rows are (ie, the number of
columns) and the size of the base type of the array, it can always
figure out the address of any one element. Since C does not have
bounds checking on arrays, it doesn't need to know the number of rows.
Since it knows the length of each row and the size of each element, it
can "skip" over the rows until it finds the element you are
requesting.

The bounding checks lack is neat. It seems C is the Barry Goldwater of
programming languages. Like like I was saying, passing the array
symbol
(using too much emacs lisp) to 'void foo(char *bar)' means that I have
to
'manually' go thru. I suppose I could use a #define, so the program
knows
where the sections are cut off, if you know what I mean. In the
function
foo, if I were to say 'printf("%s", (bar + 1));' I'd get 'oo'. Head
down
to the right spot in the array, past the null that ends 'Foo', and
I'll
get the next sequence of chars, I printf and get 'Bar'. So in other
words,
using the 'char *bar' style means I have to go thru, as though the
array
was a a strand of sausages, with the pinches being nulls.
if you want position 2,1
the compiler generates an expression to skip over two rows, which
would be
2 (rows) x 4 (things in each row) x W (width in bytes of the base
type)
then the compiler just skips over one more spot to find the 1 column
in that row.


In the general form, for an N dimension array, you need to specify all
the dimensions except the first.

e.g,

double x[3][4]...[n]

should be passed as

void f(double a[][3][4]...[n]) { }

See, when I use that, the pointer is set up so that I can kind of
treat it
like the original array, and not in the 'sausage' fashion above. Try
some
printf's to grok it.
I am not sure what you are asking in part (b). Function calls are not
that expensive.

Depends! If you are doing them again and again, that adds up. A macro
might work, but that is bloat in memory as opposed to CPU strain.
Stuff
that you want to run real fast, either because you have to (boss
said),
you want to (you are doing something like FluxBox), or you want to
look
kewl in front of all the FreeBSD and GNU/Linux users of the fairer sex
(why? duh), might want such an optimisation. Sometimes guddy nuff aint
guddy nuff.
You are not passing the whole array.

See the bit about the sizeof() use. I was aware that it is a pointer.
What
I am asking is: how can I define, within a function, a pointer to a
multidimensional array, that I can treat like a multi-dimensional
array.
If ya don't grok it yet, here are the 'sausage' and 'function' method:

Sausage:

printf("%s", (foo + 1));

Yields 'oo'.

Function:

printf("%s", (foo + 1));

Yields 'Bar'.

printf("%s", ((foo + 1) + 1));

Yields 'ar'. (Actually, my printf syntax in the last bit might be
wrong. I
could nonchalantly d'l an illegal copy of Visual C at this Windoze box
but I don't trespass into people's yards to steal pieces of stinking,
fly-eaten dog
sh*t, so I won't illegally grab a copy of VC which is equivalent
thereto, and I think I'm above theft unlike M$.)

When actually
defining an array, you must specify all the dimensions so the compiler
can generate code to allocate the correct amount of memory.

Well, yeah. I kinda figured that'n. :)

--
Top Ten Things Not to Say to a Girl, #3:

"compared to most emacs modes, this keymap you have defined for me
really
bites the bag. perhaps you could make some adjustments and
byte-compile
your e lisp source again? and my hands never got so sticky using
emacs,
why is that? you should try cold booting yourself, that fixes all lisp
problems..."

....and #8:

"STRAITER EMPY IN THE TWENTY-FOURTH-AND-A-HALF CENTURY!!!!"
 
E

Eric Sosman

Mr. Berserker said:
I was posting stuff to a mailing list when a friend, Prof. Corbessero
and I came up with this one. Perhaps you can help resolve this, or add
anything else worth knowing?? Maybe it should be added to the FAQ for
further reference... :)
[...]

I looked and looked, and couldn't find a question
anywhere in your posting. Some technical details, yes.
Some childish drivel, yes. Some snippets from what
must have been a larger explanatory context, yes --
but no question.

The only appropriate answer I can think of is:
 
K

Kevin Easton

Mr. Berserker said:
What I am asking is: how can I define, within a function, a pointer
to a multidimensional array, that I can treat like a
multi-dimensional array.

Given:

int (*foo)[2][3][10];

and:

int bar[15][2][3][10];
int baz[300][2][3][10];

You can set:

foo = bar;

and access bar[a][c][d] as foo[a][c][d], then set

foo = baz;

and access baz[a][c][d] as foo[a][c][d].

Is that what you're after?

- Kevin.
 
K

Keith Thompson

Chris Torek said:
I was posting stuff to a mailing list when a friend, Prof. Corbessero
and I came up with this one. ... [...]
So, here is what a 3x4 array looks like in memory

This is correct but only visible in strictly conforming code if
you use "unsigned char" pointers to step through all the bytes
making up the array.

So the following program isn't strictly conforming?

#include <stdio.h>

int main(void)
{
int arr[3][3];
int i, j, k;
int *ptr;

for (i = 0; i < 3; i ++) {
for (j = 0; j < 3; j ++) {
arr[j] = 10 * j + i;
}
}

ptr = (int*)arr;
for (k = 0; k < 9; k ++) {
printf("ptr[%d] = %2d", k, ptr[k]);
if (k % 3 == 2) printf("\n"); else printf(", ");
}

return 0;
}

On one implementation I tried, it produced the following output:

ptr[0] = 0, ptr[1] = 10, ptr[2] = 20
ptr[3] = 1, ptr[4] = 11, ptr[5] = 21
ptr[6] = 2, ptr[7] = 12, ptr[8] = 22

This of course proves nothing, but given the requirements in the
standard, I find it difficult to imagine a conforming implementation
producing any other output.

The cast of the address of arr to type (int*) is admittedly
suspicious; does it give an implementation enough latitude to do
something non-obvious?
 
C

Chris Torek

So the following program isn't strictly conforming?

#include <stdio.h>

int main(void)
{
int arr[3][3];
int i, j, k;
int *ptr;

for (i = 0; i < 3; i ++) {
for (j = 0; j < 3; j ++) {
arr[j] = 10 * j + i;
}
}

ptr = (int*)arr;
for (k = 0; k < 9; k ++) {
printf("ptr[%d] = %2d", k, ptr[k]);
if (k % 3 == 2) printf("\n"); else printf(", ");
}

return 0;
}


So sayeth the Standards Interpreters over in comp.std.c, yes.
In particular, ptr[3] supposedly could trap.

(Personally, I do not see how one would construct any reasonable
C implementation that traps these, yet allows functions like
memcpy() to exist. It would not bother me in the least if the
Standards Interpreters changed their minds and said this is all
fine. :) )
 
M

Mr. Berserker

Eric Sosman said:
Mr. Berserker said:
I was posting stuff to a mailing list when a friend, Prof. Corbessero
and I came up with this one. Perhaps you can help resolve this, or add
anything else worth knowing?? Maybe it should be added to the FAQ for
further reference... :)
[...]

I looked and looked, and couldn't find a question
anywhere in your posting. Some technical details, yes.
Some childish drivel, yes. Some snippets from what
must have been a larger explanatory context, yes --
but no question.

The only appropriate answer I can think of is:

As per usual, someone on USENET has an attitude, which, if turds were
as big as it, would result in bog paper the size of the Bayeux
Tapestry, and bog rolls that are actually converted cement mixer
drums.
 
M

Mr. Berserker

Kevin Easton said:
Mr. Berserker said:
What I am asking is: how can I define, within a function, a pointer
to a multidimensional array, that I can treat like a
multi-dimensional array.

Given:

int (*foo)[2][3][10];

and:

int bar[15][2][3][10];
int baz[300][2][3][10];

You can set:

foo = bar;

and access bar[a][c][d] as foo[a][c][d], then set

foo = baz;

and access baz[a][c][d] as foo[a][c][d].

Is that what you're after?


I thought that was only good for moving thru whole arrays; didn't
something to that turn up in the C FAQ? Well, I'll fire up emacs and
gcc once I get home and see how it goes... Thx for the advice! :)
 
K

Keith Thompson

Chris Torek said:
So the following program isn't strictly conforming?
[snip]

So sayeth the Standards Interpreters over in comp.std.c, yes.
In particular, ptr[3] supposedly could trap.

(Personally, I do not see how one would construct any reasonable
C implementation that traps these, yet allows functions like
memcpy() to exist. It would not bother me in the least if the
Standards Interpreters changed their minds and said this is all
fine. :) )

I wonder how even an unreasonable C implementation could break this
while still conforming to the standard. Hmm. I suppose it could
store bounds information in pointers, and propagate the bounds of the
first row of arr to ptr on the assignment.

I wonder how the DS-9000 handles this.
 
A

Arthur J. O'Dwyer

Keith Thompson said:
So the following program isn't strictly conforming?
int arr[3][3];
int *ptr;
ptr = (int*)arr;
for (k = 0; k < 9; k ++) {
printf("ptr[%d] = %2d", k, ptr[k]);

So sayeth the Standards Interpreters over in comp.std.c, yes.
In particular, ptr[3] supposedly could trap.

(Personally, I do not see how one would construct any reasonable
C implementation that traps these, yet allows functions like
memcpy() to exist. It would not bother me in the least if the
Standards Interpreters changed their minds and said this is all
fine. :) )

I could conceive of a bounds-checking implementation that had no
bounds checking on pointers to void. On such an implementation
with optimization turned off, the clever-newbie workaround would
be

int *ptr = (void*)arr; /* cast to int* w/o bounds checking */

but since AFAIK no implementation actually does this, c.l.c is
saved from having to explain why the above is silly in the extreme.

:)
-Arthur
 
M

Mr. Berserker

Chris Torek said:
You do not say who wrote this, but it is quite wrong.

Fortran uses column-major order; C uses row-major order.


This is correct but only visible in strictly conforming code if
you use "unsigned char" pointers to step through all the bytes
making up the array.


C compilers are allowed to do bounds-checking, and some do.

Hm, you are BSD I see? Wind Rivers, aren't they embedded developers of
BSD? Don't most BSD'ers user gcc? I am using gcc right now. Since I
don't use non-free softwares including angband and xfig, gcc is all I
really concern myself with. Last time I checked gcc, doesn't do bounds
checking. I'd need to check again...
 
M

Mr. Berserker

Chris Torek said:
You do not say who wrote this, but it is quite wrong.

Fortran uses column-major order; C uses row-major order.


This is correct but only visible in strictly conforming code if
you use "unsigned char" pointers to step through all the bytes
making up the array.

Woops, forgot to ask this: what is the difference between signed and
unsigned char *? Is it just good programming practise? (Unless your
architecture has negative address space...)
 
C

Chris Torek

Hm, you are BSD I see? Wind Rivers, aren't they embedded developers of
BSD? Don't most BSD'ers user gcc?

Wind River do sell an embedded BSD, and all the BSDs (there are
many, and even MacOS X can be considered a "BSD" in various ways)
do currently use gcc. We also sell the Diab compilers, which I
have not worked on myself.
... Last time I checked gcc, doesn't do bounds
checking. I'd need to check again...

Google search for "bounds checking" "gcc" turned up quite a few
links, including:

<http://gcc.gnu.org/projects/bp/main.html>
<http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html>
<http://web.inter.nl.net/hcc/Haj.Ten.Brugge/>

The last of these claims to support gcc 3.x.
 

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

Forum statistics

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