www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - C-binding external array.

reply ciechowoj <keepitsimplesirius gmail.com> writes:
Is there a way to access a static array from D without knowing 
the size of the array?

Let suppose there is an array, somewhere in lib.c.

int tab[64];

and there is header file lib.h with following reference:

extern int tab[];

How to declare `tab` in the D code without knowing the size of 
the array? In other words, how to map external declaration of the 
`tab` to the D code?
Aug 09 2016
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 8/9/16 9:53 AM, ciechowoj wrote:
 Is there a way to access a static array from D without knowing the size
 of the array?

 Let suppose there is an array, somewhere in lib.c.

 int tab[64];

 and there is header file lib.h with following reference:

 extern int tab[];

 How to declare `tab` in the D code without knowing the size of the
 array? In other words, how to map external declaration of the `tab` to
 the D code?
I think this should work: extern extern(C) int[1] tab; Then if you want to access the elements, use the tab.ptr[elem] If it's a global variable, tack on __gshared. -Steve
Aug 09 2016
parent reply ciechowoj <keepitsimplesirius gmail.com> writes:
On Tuesday, 9 August 2016 at 14:01:17 UTC, Steven Schveighoffer 
wrote:
 I think this should work:

 extern extern(C) int[1] tab;

 Then if you want to access the elements, use the tab.ptr[elem]

 If it's a global variable, tack on __gshared.

 -Steve
I've already tried this and works (64-bit at least on linux). But is it portable? No other way that allow to access the `tab` directly (without .ptr proxy) ?
Aug 09 2016
next sibling parent reply Kagamin <spam here.lot> writes:
Well
extern extern(C) __gshared int[64] tab;
Aug 09 2016
parent ciechowoj <keepitsimplesirius gmail.com> writes:
On Tuesday, 9 August 2016 at 14:25:15 UTC, Kagamin wrote:
 Well
 extern extern(C) __gshared int[64] tab;
My assumption is you do not know the size of the array.
Aug 09 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 8/9/16 10:09 AM, ciechowoj wrote:
 On Tuesday, 9 August 2016 at 14:01:17 UTC, Steven Schveighoffer wrote:
 I think this should work:

 extern extern(C) int[1] tab;

 Then if you want to access the elements, use the tab.ptr[elem]

 If it's a global variable, tack on __gshared.
I've already tried this and works (64-bit at least on linux). But is it portable?
Yes. D is designed to interface with C in certain ways, and this should be portable.
 No other way that allow to access the `tab` directly (without ..ptr
 proxy) ?
Well, you can via properties: property int* tabp() { return tab.ptr; } tabp[elem]; Essentially, tab is a symbol that points at some undetermined number of elements. Since it's undetermined, D doesn't allow safe easy access. If you did int *tab, then it would think the symbol points at a pointer. tab.ptr is a shortcut to &tab[0]. You could potentially do int tab, and then use (&tab)[elem]. Or if you know the number of elements, you can just declare them. If it were me, I'd access it via tab.ptr, because it *is* an unsafe operation and I'd want to highlight that for future readers. If something defines tab's length, I'd highly recommend wrapping the two: extern(C) int tabLength(); // mythical mechanism or no? property int[] dtab { return tab.ptr[0 .. tabLength]; } -Steve
Aug 09 2016
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 8/9/16 11:41 AM, Steven Schveighoffer wrote:

 extern(C) int tabLength(); // mythical mechanism or no?

  property int[] dtab { return tab.ptr[0 .. tabLength]; }
And I've used mythical syntax also! Should be: property int[] dtab() { return tab.ptr[0 .. tabLength]; } -Steve
Aug 09 2016
prev sibling parent reply ciechowoj <keepitsimplesirius gmail.com> writes:
On Tuesday, 9 August 2016 at 15:41:08 UTC, Steven Schveighoffer 
wrote:
 Well, you can via properties:

  property int* tabp() { return tab.ptr; }

 tabp[elem];
This is nice. The best would be to have it with the same name as original symbol, but I can't imagine how it could be done.
 Essentially, tab is a symbol that points at some undetermined 
 number of elements. Since it's undetermined, D doesn't allow 
 safe easy access.

 If you did int *tab, then it would think the symbol points at a 
 pointer.

 tab.ptr is a shortcut to &tab[0].

 You could potentially do int tab, and then use (&tab)[elem].

 Or if you know the number of elements, you can just declare 
 them.

 If it were me, I'd access it via tab.ptr, because it *is* an 
 unsafe operation and I'd want to highlight that for future 
 readers.

 If something defines tab's length, I'd highly recommend 
 wrapping the two:

 extern(C) int tabLength(); // mythical mechanism or no?

  property int[] dtab { return tab.ptr[0 .. tabLength]; }
And this is even better. However, I suppose you are right and I should stick to `tab.ptr`.
Aug 09 2016
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 8/9/16 2:46 PM, ciechowoj wrote:
 On Tuesday, 9 August 2016 at 15:41:08 UTC, Steven Schveighoffer wrote:
 Well, you can via properties:

  property int* tabp() { return tab.ptr; }

 tabp[elem];
This is nice. The best would be to have it with the same name as original symbol, but I can't imagine how it could be done.
D has an answer: pragma(mangle, "tab") extern extern(C) int[1] _ctab; property int* tab() { return _ctab.ptr; } I still don't recommend doing this, for previously stated reasons. -Steve Disclaimer: D does not always have an answer. It only has MOST of the answers.
Aug 09 2016
parent reply ciechowoj <keepitsimplesirius gmail.com> writes:
On Tuesday, 9 August 2016 at 19:16:42 UTC, Steven Schveighoffer 
wrote:
 D has an answer:

 pragma(mangle, "tab")
 extern extern(C) int[1] _ctab;

  property int* tab() { return _ctab.ptr; }

 I still don't recommend doing this, for previously stated 
 reasons.
This is really interesting :).
Aug 10 2016
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 08/10/2016 02:05 AM, ciechowoj wrote:
 On Tuesday, 9 August 2016 at 19:16:42 UTC, Steven Schveighoffer wrote:
 D has an answer:

 pragma(mangle, "tab")
 extern extern(C) int[1] _ctab;

  property int* tab() { return _ctab.ptr; }

 I still don't recommend doing this, for previously stated reasons.
This is really interesting :).
Better with some mixin magic: mixin template CArray(string symbol, T) { pragma(mangle, symbol) extern extern(C) __gshared mixin ("T[0] _c" ~ symbol ~ ";"); property mixin ("T* " ~ symbol ~ "() { return _c" ~ symbol ~ ".ptr; }"); } mixin CArray!("tab", int); tab[42] = 42; Ali
Aug 10 2016
parent ciechowoj <keepitsimplesirius gmail.com> writes:
On Wednesday, 10 August 2016 at 15:07:52 UTC, Ali Çehreli wrote:
 On 08/10/2016 02:05 AM, ciechowoj wrote:
 Better with some mixin magic:

 mixin template CArray(string symbol, T) {
     pragma(mangle, symbol) extern extern(C) __gshared
     mixin ("T[0] _c" ~ symbol ~ ";");

      property
     mixin ("T* " ~ symbol ~ "() { return _c" ~ symbol ~ ".ptr; 
 }");
 }

 mixin CArray!("tab", int);

 tab[42] = 42;
This is very tempting to use. The only thing that stops me from doing that is I am unsure if the 'property' tab behaves in all contexts the same way the standard array behaves.
Aug 10 2016
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 08/09/2016 11:46 AM, ciechowoj wrote:
 On Tuesday, 9 August 2016 at 15:41:08 UTC, Steven Schveighoffer wrote:
  property int* tabp() { return tab.ptr; }

 tabp[elem];
This is nice. The best would be to have it with the same name as original symbol, but I can't imagine how it could be done.
Well, C's array symbol is used as a pointer to the first element and D allows array indexing for pointers as well. Here is the C code: // c.c #include "stdio.h" int tab[64]; int *get() { return tab; // or &tab[0] } void info() { printf("%p\n", tab); } void write_at(int i, int value) { tab[i] = value; } int read_at(int i) { return tab[i]; } The D code uses the array as a pointer and then makes a slice at the very end: // d.d import std.stdio; extern (C) { int *get(); void info(); void write_at(int i, int value); int read_at(int i); } void main() { int *tab = get(); info(); writefln("0x%s", tab); // make sure we can see what C writes write_at(7, 77); assert(tab[7] == 77); // make sure C can read what we write tab[42] = 42; assert(read_at(42) == 42); // If you know the size, use as a D array int[] tab_D = tab[0..64]; writeln(tab_D); } Ali
Aug 09 2016
parent ciechowoj <keepitsimplesirius gmail.com> writes:
On Tuesday, 9 August 2016 at 19:16:46 UTC, Ali Çehreli wrote:
 Well, C's array symbol is used as a pointer to the first 
 element and D allows array indexing for pointers as well.

 Here is the C code:

 // c.c
 #include "stdio.h"

 int tab[64];

 int *get() {
     return tab;    // or &tab[0]
 }

 void info() {
     printf("%p\n", tab);
 }

 [...]
The problem is, I do not have a control over the C source code.
Aug 10 2016