From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: 103376,6b3a3c920575b35a X-Google-Attributes: gid103376,public X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news3.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!wn14feed!worldnet.att.net!bgtnsc04-news.ops.worldnet.att.net.POSTED!53ab2750!not-for-mail From: Dave Thompson Newsgroups: comp.lang.ada Subject: Re: How to pass two dimensional arrays to C Message-ID: References: <1154084819.088112.325730@p79g2000cwp.googlegroups.com> <1154119563.642347.13670@b28g2000cwb.googlegroups.com> <6lByg.12373$1Z5.8869@twister.nyroc.rr.com> X-Newsreader: Forte Agent 1.93/32.576 English (American) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Date: Mon, 14 Aug 2006 06:59:41 GMT NNTP-Posting-Host: 12.76.16.187 X-Complaints-To: abuse@worldnet.att.net X-Trace: bgtnsc04-news.ops.worldnet.att.net 1155538781 12.76.16.187 (Mon, 14 Aug 2006 06:59:41 GMT) NNTP-Posting-Date: Mon, 14 Aug 2006 06:59:41 GMT Organization: AT&T Worldnet Xref: g2news2.google.com comp.lang.ada:6197 Date: 2006-08-14T06:59:41+00:00 List-Id: On Sat, 29 Jul 2006 04:19:14 GMT, "REH" wrote: > > "Jerry" wrote in message > news:1154119563.642347.13670@b28g2000cwb.googlegroups.com... > > Thanks for everyone's comments. I have thin bindings to PLplot nearly > > complete except for this nagging 2D array thing. (I also have a partial > > thick binding plus some easy-to-use one-line plotters as well.) > > > With respect to everyone, I believe you being led a little astray. C does > have multidimensional arrays. The problems they are at a lower level than Basically agree. > Ada's array, and less convenient. For you to call C, and send it an array > from Ada, you have to deal with a few issues: > 1. When used as a function parameter, an array will "decay" to a pointer to > the first element of the array. This can be inconvenient because > information about the size and dimensions of the array are lost. Arrays are > not "first class" citizens. You can make them so by wrapping them in > structs, but this only works if you know the dimensions at compile type. > So, that is limited use. Exactly. > 2. What "type" of array? There can be a couple of different types in C, > because of their close relationship to pointers. One type is the simple > contiguous array: a[x][y]; Though, one might argue that this is not a 2d > array, but an array of arrays. That's just semantics, and doesn't matter. > The elements will be layed out the same assuming the elements are the same > and row major ordering is used (so, for Fortran, you would reverse the > dimensions, since it uses column major ordering). The second type is called > a jagged array, which is an array of pointers. You can simulate this form > in Ada using an array of access types to the second dimension. And for both > languages, an access to and element of the jagged array uses that same > syntax as a 2d array. Almost. In C ary-of-ary and ary-of-ptr(-for-ary) are both X [I] [J]. In Ada array-of-array is X (I) (J) and so is array-of-access-to-array since the dereference is implied; but true 2D array is X (I, J). > 3. Are the dimensions constant? As long as all but the first dimension is > constant, it is simply a matter of giving C a pointer to an object whose > type is your array type minus the first dimension (again, assume the memory Canonically, right. > is layed out the same). So, if in Ada we have (ignoring necessay pragmas > and/or rep. specs.): > > type A is array (1 .. 10, 1 .. 10) of Interface.C.int; > type pA is access all A; > > we can map this in C several ways. One easy to understand way is: > But to be clear, NOT the way you just said (drop the first dimension). > typedef A[10][10]; > > void foo(A* P); > > this would map to an Ada procedure thus: > > procedure foo(P : in pA); > > This has the advantage of C "knowing" the dimensions, but is inconvenient > because because P has to be dereferenced before dimensions may be applied: > (*P)[1][2]; *** remember that the dimensions now in C, so the ranges for > both are 0 to 9. > > Another way would be: > > typedef A[10]; > > void foo(A* P); > > To map this, we must either use System.Address and lose type safety or > change A to be an array of array and use an access type to the second > dimension array (messy). > > procedure foo(P : in System.Address); > > call foo with A[1,1]'Address. > Surely you mean someA (1,1) 'Address . > This makes the C code nicer, in that we can now just say P[1][2]; > Aside: You don't need the typedef's in C. They _don't_ create really new types, only aliases/abbreviations. (But I'm fine with using them for the pedagogical example, as they allow you to discuss different points (!) separately.) > Both methods assume the dimensions are constant. If only the first > dimension is variable, use the second method above, and send C that > dimension via another parameter. If both dimensions are variable, this is > more problematic because C cannot define array types with variable > dimensions. All this means is that you have to calculate the indexing As of C99 it can standardly, and although complete C99 implementations are not common, some features including this one (called Variable Length Arrays for the actual objects, and Variably Modified types for some of the other types related to them like pointers) are becoming common, and indeed were in GCC even before C99. > yourself. This is a pain and error-prone, but at least it is not > insurmountable. For example (assume the element type is still int): > Of course, doing this way (by hand) is still perfectly legal also. > foo(void* P, int x, int y); > Probably better unsigned /*int*/, or even better size_t. Dimensions cannot be negative, and cannot validly be zero; C doesn't have Positive, but it does (almost) have Natural. > Here we calculate P[1][2] thus: > > const sx = sizeof(int) * y; > const sy = sizeof(int); const int (or better size_t) in C99; implicit int is (finally!) gone, and types are NOT automatic like they are in Ada renames -- although a fairly similar feature is being considered for _C++_. But per your correction the sizeof(int) factors aren't needed anyway. > int* I = P; > int v = P + sx * 1 + sy * 2; *** again, remembering that the dimensions are > now zero-based. > There's no need to pass the base pointer as void* and then convert it to whatever*. Unless you are trying to make a type-generic utility routine(s), and you can't really do that right in C, so barring exigent circumstances I wouldn't confuse matters by trying. > Messy, but doable. You should create a function to do the indexing and > return the element. If using C99, make it inline. > I don't think it's worth making it a function. But then I've needed to do manual-Ndim in enough languages (and systems) back to early FORTRAN and BASIC that it's almost subconscious. But I agree make it inline if you do. (Again actually supported in a lot of compilers that don't support all of C99. But not all. But then you can easily enough #define it away it necessary) > Jagged arrays are even messier. These are just arrays of pointers. They > allow the creation of arrays where the second dimension is of varying > length. The problem is that C will not intrinsically know the lengths, and > thus you will probably have to give it an array of lengths as a second > parameter. But, most likely, if you are going from Ada to C, you aren't > dealing with these. > - David.Thompson1 at worldnet.att.net