Thread overview
constant pointer failing to compile
Apr 06, 2023
Josh Holtrop
Apr 06, 2023
Mathias LANG
Apr 06, 2023
Josh Holtrop
Apr 06, 2023
Salih Dincer
Apr 06, 2023
Jacob Shtokolov
Apr 06, 2023
Jacob Shtokolov
April 06, 2023

I am trying to port a small C project to D and am getting a compilation error I don't understand.

I've simplified the situation down to the example here.

This C version compiles fine:

#include <stdio.h>

static const unsigned char data[] = {1, 2, 3, 4};

static const unsigned char * p = &data[0];

int main(int argc, char * argv[])
{
    printf("*p = %u\n", *p);
    return 0;
}

My attempt to do the same in D:

import std.stdio;

__gshared immutable ubyte[] data = [1, 2, 3, 4];

__gshared immutable ubyte * p = data.ptr;

int main()
{
    writeln("*p = ", *p);
    return 0;
}

This fails to compile with gdc:

constarrptr.d:5:45: error: cannot use non-constant CTFE pointer in an initializer ‘&[cast(ubyte)1u, cast(ubyte)2u, cast(ubyte)3u, cast(ubyte)4u][0]’
    5 | __gshared immutable(immutable(ubyte) *) p = data.ptr;
      |                                             ^

And also with ldc2:

constarrptr.d(5): Error: cannot use non-constant CTFE pointer in an initializer `cast(immutable(ubyte)*)data`

Why? And how can I do the equivalent to what I have been doing in C? I want these pointers to be generated at compile time, not initialized at runtime.

(the full project is generating this file containing the data array (which is much longer) and multiple pointer constants to locations within it)

April 06, 2023
>

immutable ubyte[4] data = [1, 2, 3, 4];

Using a static array instead of a slice will do the trick. You can leave the __gshared if you want, but it is redundant on a global, initialized immutable variable.

April 05, 2023

On 4/5/23 8:59 PM, Mathias LANG wrote:

> >

immutable ubyte[4] data = [1, 2, 3, 4];

Using a static array instead of a slice will do the trick. You can leave the __gshared if you want, but it is redundant on a global, initialized immutable variable.

I found out the same thing. But I don't really understand why.

the error message gives a slight clue:

cannot use non-constant CTFE pointer in an initializer ‘&[cast(ubyte)1u, cast(ubyte)2u, cast(ubyte)3u, cast(ubyte)4u][0]’

That isn't a CTFE pointer, it's a pointer to a static immutable. Yes, the initialization value is a CTFE array, but the variable itself has an address. Notice how the expression has turned into an address of the initializer.

I think this is a compiler bug.

-Steve

April 06, 2023

On Thursday, 6 April 2023 at 00:59:12 UTC, Mathias LANG wrote:

> >

immutable ubyte[4] data = [1, 2, 3, 4];

Using a static array instead of a slice will do the trick. You can leave the __gshared if you want, but it is redundant on a global, initialized immutable variable.

Yes, thank you, using static arrays did work. And thanks for the note on __gshared as well.

April 06, 2023

On Thursday, 6 April 2023 at 00:46:26 UTC, Josh Holtrop wrote:

>
constarrptr.d(5): Error: cannot use non-constant CTFE pointer in an initializer `cast(immutable(ubyte)*)data`

Why? And how can I do the equivalent to what I have been doing in C? I want these pointers to be generated at compile time, not initialized at runtime.

(the full project is generating this file containing the data array (which is much longer) and multiple pointer constants to locations within it)

You have 2 options: First, to use .ptr, or second, to do the initialization in static this:

import std.stdio;

static const char[] d;
static const char * p;

static this() {
  d = [97, 98, 99];
  p = &d[0]; // == d.ptr;
}

void main()
{
  printf("%.*s\n", cast(int)d.length, d.ptr);
  writeln("*p = ", *p);
}/* Prints:

  abc
  *p = a

*/

SDB@79

April 06, 2023

On Thursday, 6 April 2023 at 00:46:26 UTC, Josh Holtrop wrote:

>

I am trying to port a small C project to D and am getting a compilation error I don't understand.

It seems like the compiler is just missing some type hints. Try this:

import std.stdio;

__gshared immutable ubyte[4] data = [1, 2, 3, 4];

__gshared immutable ubyte* p = data.ptr;

int main()
{
    writeln("*p = ", *p);
    return 0;
}

Look how I provided the ubyte[4] hint to the compiler so it thinks that it's a constant.

I'm not sure why this happens, but sometimes the compiler can't deduce static arrays, especially if you're explicitly saying that they're not static (ubyte[]).

April 06, 2023

On Thursday, 6 April 2023 at 20:23:29 UTC, Jacob Shtokolov wrote:

>

On Thursday, 6 April 2023 at 00:46:26 UTC, Josh Holtrop wrote:

>

I am trying to port a small C project to D and am getting a

Ah, just noticed that other people have already responded! Sorry about that!
BTW, your &data[0] C-like pointer will also work in D's version, although it's probably a bit uglier.