0

The code below fails to compile with "initializer element is not constant", or similar on gcc and clang.

Is there any way to make z even more constant? It's already a static constant pointer to constant characters.

Can this be made to work (in a standards compliant way) or is it a violation of the standard?

static const char * const z = "1234";
const struct {
    const char * a;
} b = {z};

My specific use case is closer to

const struct {
    char x[5];
    char y[5];
} n = {"12345","abcde"};
static const char * const z = n.x;
const struct {
    const char * a;
} b = {z};

Actually I'd be happier if I could define an alias, something like this

const char z[5] = n.x;

which is bad syntax, but ....

Martin
  • 911
  • 7
  • 21
  • your example code works in C++. Investigating C... – bolov Jan 11 '15 at 07:55
  • unfortunately I need code that works in both C and C++, I already had to omit named struct initialization, because C++ doesn't support it. – Martin Jan 11 '15 at 08:00
  • http://stackoverflow.com/questions/21592494/initializer-element-is-not-constant-error-for-no-reason-in-linux-gcc-compilin – bolov Jan 11 '15 at 08:03
  • @bolov so basically, it can't be done in C? – Martin Jan 11 '15 at 08:09
  • haven't read the whole post but for what I gathered it looks like no, but I wouldn't say that for sure. – bolov Jan 11 '15 at 08:11
  • @bolov thanks, I'll work around it, a few dozen more ifdefs shouldn't be all that bad, just ugly and slow. – Martin Jan 11 '15 at 08:15

3 Answers3

0

Here's the closest you can get to the specific use case.

#include <stdio.h>

const struct
{
    char x[6];
    char y[6];
}
    n = { "12345", "abcde" };

static const char * const z = n.x;
const struct
{
    const char * const *a;
}
    b = { &z };

int main( void )
{
    printf( "%s\n", *b.a );
}

The address of a previously-declared static-or-global object is always a compile-time constant. So you can assign &z to a provided that a is a pointer-to-a-pointer.

user3386109
  • 34,287
  • 7
  • 49
  • 68
  • your code is missing the intermediate variable, which is the key, I know it works without the intermediate variable. And I'm not concerned about NULs, my arrays are unsigned chars and are hex values, the snippet is just a simplification. – Martin Jan 11 '15 at 08:05
  • @Martin Ok, I gave it another shot. – user3386109 Jan 11 '15 at 08:12
  • still no good, I'd have to change a lot of code and all of it would have to do an extra dereference. It works, but it's not a solution to my problem unfortunately. – Martin Jan 11 '15 at 08:14
0

You could use a macro:

struct P {
  char x[5];
  char y[5];
};

#define X(_n, _z, s1, s2) \
  const struct P _n = {s1, s2}; \
  static const char _z[] = s1;

X(n, z, "12345", "abcde")

const struct 
{
  const char * a;
} b = {z};

The pre-prcoessor would create the following:

const struct P n = {"12345", "abcde"}; 
static const char z[] = "12345";

const struct {
  const char * a;
} b = {z};

This compiles perfectly fine.

alk
  • 69,737
  • 10
  • 105
  • 255
  • which is what I'm trying to avoid, I need some binary data both in a packed struct (to avoid having to do memcpy 5 times) and referred separately without duplicating the data and without relying on the compiler removing the duplicates. – Martin Jan 11 '15 at 13:10
  • @Martin Then what is the intention of `const char z[5] = n.x;` (as per your question's snippets), if not duplicating data? – alk Jan 11 '15 at 13:16
  • I wasn't clear, I was hoping for something like C++ references, a pointer with size, so sizeof(z) returns 5 instead of sizeof(void*). – Martin Jan 11 '15 at 13:20
  • But `char z[5]` defines a `char` array of 5 elements, not a "reference" (which does not exist in C), nor a pointer. @Martin – alk Jan 11 '15 at 13:22
  • I know, but say the array contains about a hundred bytes which I don't want to duplicate, but I want to have it inside a packed struct (with other byte arrays), but also refer to it and get its size easily. ... I know C doesn't have references, and C++ doesn't have named initialization, and my code needs to work in both, so I'm trying to work around things, and also make the code readable and maintainable and optimal (no duplication, decent speed, no asm)... and I forgot portable. – Martin Jan 11 '15 at 13:26
0
const struct {
    char x[5];
    char y[5];
} n = {"12345","abcde"};
#define z   n.x
const struct {
    const char * a;
} b = {z};
#include <stdio.h>
int main(void)
{
    printf("%.5s == %.5s == %.5s\n", b.a, z, n.x);
}

The #define meets all stated requirements:

  • It is C and C++ standard conforming.
  • It is an alias, if you want to call it so.
  • It is as constant as it gets.
  • The data in structure n is not duplicated.
  • sizeof z is 5.
  • It is readable and maintainable and portable.
Armali
  • 18,255
  • 14
  • 57
  • 171