Jump to page: 1 2
Thread overview
C-binding external array.
Aug 09, 2016
ciechowoj
Aug 09, 2016
ciechowoj
Aug 09, 2016
Kagamin
Aug 09, 2016
ciechowoj
Aug 09, 2016
ciechowoj
Aug 10, 2016
ciechowoj
Aug 10, 2016
Ali Çehreli
Aug 10, 2016
ciechowoj
Aug 09, 2016
Ali Çehreli
Aug 10, 2016
ciechowoj
August 09, 2016
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?



August 09, 2016
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
August 09, 2016
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) ?
August 09, 2016
Well
extern extern(C) __gshared int[64] tab;
August 09, 2016
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.
August 09, 2016
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
August 09, 2016
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

August 09, 2016
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`.



August 09, 2016
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.
August 09, 2016
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

« First   ‹ Prev
1 2