3

I'm getting initialization discards ‘const’ qualifier from pointer target type warning in the line .grid_col = &c_ax_gd i.e. assigning an address expression to a pointer, which is part of a constant structure.

struct color {
    double r;
    double g;
    double b;
    double a;
};
struct graph {
    double origin[2];
    double dim[2];
    double scale[2];
    double grid_line_width;
    double axes_line_width;
    struct color *grid_col;
    struct color *axes_col;
};

int main(void) {
    static const struct color c_ax_gd = {0.5, 0.5, 0.5, 1};
    static const double h = 600, w = 800;
    const struct graph g = {
            .origin = {w / 2, h / 2},
            .dim = {w, h},
            .scale = {w / 20, h / 20},
            .grid_line_width = 0.5,
            .axes_line_width = 1,
            .grid_col = &c_ax_gd,
            .axes_col = &c_ax_gd
    };
    ....
}

I found the following in C99 standard

More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:

  • an arithmetic constant expression,
  • a null pointer constant,
  • an address constant, or
  • an address constant for an object type plus or minus an integer constant expression.

An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type

My question is, doesn't that mean &c_ax_gd is an address constant? If so, how does using an address constant inside an initializer for a constant structure discards the const qualifier?

Samik
  • 575
  • 2
  • 8
  • 19

2 Answers2

4

The problem is somewhere else. Even if a struct is const, if it has pointers as members, the objects those pointers point to are not automatically const. You can see that from the following example.

struct example {
  int * p;
};

int
main()
{
  /* const */ int a = 1;
  const struct example s = {&a};
  *(s.p) = 2;
  return 0;
}

Therefore, if you uncomment the /* const */ and assign the address of a to s.p, you're discarding the const qualifier on a. That's what your compiler warns you about.

5gon12eder
  • 24,280
  • 5
  • 45
  • 92
2

g is const, which means all its members are const (including grid_col). So grid_col is a const pointer to struct color and &c_ax_gd is a pointer to const struct color.

You are tryting to initialize const struct color pointer with a struct color pointer and that's why you get the warning.

C99 6.5.16.1

both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right

If you ignore the warning, you'll just get undefined behavior if you modify the value grid_col points to.

martinkunev
  • 1,364
  • 18
  • 39
  • Doesn't declaring a structure as `const` make its members `const`? – Samik Feb 14 '16 at 08:50
  • 1
    @Samik Yes, all its members are const. The problem is that if some of these members are pointers, they are just const pointers (you can't change the pointer; there are no restrictions applied to the values they point to). You can check this: http://stackoverflow.com/questions/10091825/constant-pointer-vs-pointer-on-a-constant-value – martinkunev Feb 14 '16 at 08:53
  • Thanks, totally missed that one, how silly of me. Upvoted your answer. – Samik Feb 14 '16 at 08:59
  • The warning is part of the standard (specifically, that a diagnostic be issued; the code is a constraint violation) – M.M Feb 14 '16 at 09:43