In article <news:a7729fbc.0401211322.f8541e@posting.google.co m>
Charles Banas <greywolf@the-junkyard.net> writes:
[snippage; just key parts retained][color=blue]
> static float bbuff[TBUF_SIZE][60][60];
> float buff[60][60];
> register char *r1buff;
> register char *r2buff;
>
> r1buff = (char *) & (buff[0][0]);
> r2buff = (char *) & (bbuff[i][0][0]);
>
> for (j = 0;j < 3600;j++, r1buff++, r2buff++)
> *r1buff = *r2buff;
>
> /* memcpy((char *)&(buff[0][0]),
> (char *)&(bbuff[i][0][0]),
> sizeof(float)*3600); */
>
>now you can see that the memcpy was originally tried, but later
>dumped, likely because of how C arrays work. but the for loop caught
>my attention: they're basically just copying bewteen two
>de-referenced pointers. is this kosher?[/color]
Let me answer this in code order, rather than question order.
First, the loop version runs j from 0 up to (but not including)
3600, and 3600 is 60*60. The two pointers here have type "char *",
and the loop is indeed similar to the commented-out memcpy --
but they are also quite different. The "for" loop copies 3600
bytes (C bytes, "sizeof char" being 1 even if CHAR_BIT > 8).
If the memcpy() call were to be uncommented, it would copy
3600 * sizeof(float) bytes.
These are the same if and only if sizeof(float) is 1. On most
implementations, including all those supported by GCC, sizeof(float)
is at least 4.
As for whether the loop is "kosher", the strict ANSI/ISO C answer
is apparently "no". After looping over the first 60*sizeof(float)
bytes in the arrays named buff[0] and bbuff[i][0], the next accesses
are to elements in adjacent but different arrays, buff[1] and
bbuff[i][1]. Some over in comp.std.c say this is allowed to
fail with an "out of array bounds" type of exception. Somewhat
more realistically, plain char might be signed char, which might
have problems copying data -- on ones' complement systems like
the Univac, all-1s bit patterns (-0) might be turned into all-0s
(+0), ruining the "float" value. This part is easily fixed, by
using "unsigned char *" instead of plain "char *".
Certainly the memcpy() call, and most likely even just use of
"unsigned char *", will avoid any sort of "out of array bounds"
exception that might be allowed. (I remain somewhat skeptical that
they even *are* allowed.) On most practical machines, too, even
plain "char *" copies will "work right".
[color=blue]
>i know it works with both
>Visual C++ 6 and GCC 3.3, but to me, it doesn't look like it should
>work. can someone explain to me why the buffer copies correctly and
>successfully despite the rather strange-looking method?[/color]
The fact that C does not *have* multidimensional arrays is important.
Instead, C has arrays whose elements are in turn arrays. Here
bbuff is an object whose type is "array TBUF_SIZE of <something>",
and the <something> is in turn another array type: "array 60 of
<something2>". Here <something2> is yet another array type: "array
60 of float", and now it stops, because "float" is a fundamental
C type. Arrays in C (which are by definition "1 dimensional" even
if the element-type is another array) are just contiguously-arranged
elements: a[0] is immediately followed in memory by a[1], which is
immediately followed by a[2], and so on. (This is why so many
"struct"s have padding built into them at the end: in order to go
into an array, a[1] *must* come right after a[0], so if a[0] is a
struct, and that struct would need padding between adjacent array
elements, the padding must be part of the struct type. The array
is not allowed to introduce the padding!)
Now, if a[0] is immediately followed by a[1], and if a[0] is itself
an array of (say) size 2, then a[0][0] is immediately followed by
a[0][1], which -- logically -- must be immediately followed by
a[1][0]. In other words, the memory-picture:
+-----------------------+
a: | a[0][0] | a[0][1] |
| a[1][0] | a[1][1] |
+-----------------------+
can always be "linearized":
+-----------------------------------------------+
a: | a[0][0] | a[0][1] | a[1][0] | a[1][1] |
+-----------------------------------------------+
In the above code, copying 3600 / sizeof(float) -- probably 3600/4
or 900 -- elements starting from bbuff[i][0][0] will copy bbuff[i][0][0]
through bbuff[i][14][59] into buff[0][0] through buff[14][59]
respectively (assuming the 900 number is correct; and note that
900 is 15 * 60). Apparently this suffices for whatever tasks are
being run now.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it
http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.