• why can change element of a const typed struct ?

    From Denis Dos Santos Silva@denis@roo.com.br to comp.std.c on Mon Sep 18 08:49:12 2023
    From Newsgroup: comp.std.c

    hi all!
    why this works? =)



    /// image.c
    /// ...
    typedef struct {
    int w;
    int h;
    unsigned char channels;
    unsigned char *data;
    int err;
    } image_t;

    int image_copy(const image_t* source, const image_t* target, int xoffset, int yoffset) {
    register int sindex;
    register int tindex = 0;
    register int y1, x1;

    if (!source || !target)
    return -1;

    for (int y=0; y<target->h; y++) {
    for (int x=0; x<target->w; x++) {
    #if 1
    y1 = y+yoffset;
    x1 = x+xoffset;

    sindex = (y1 * source->w + x1) * 3;
    if (sindex > (source->w * source->h * 3))
    continue;

    // change value of element of const struct

    source->data[sindex+0] = target->data[tindex++];
    source->data[sindex+1] = target->data[tindex++];
    source->data[sindex+2] = target->data[tindex++];
    #endif
    }
    }

    return 0;
    }
    /// <eof>
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From David Brown@david.brown@hesbynett.no to comp.std.c on Mon Sep 18 20:29:06 2023
    From Newsgroup: comp.std.c

    On 18/09/2023 17:49, Denis Dos Santos Silva wrote:
    hi all!
    why this works? =)


    Your image_t is const, but it has a non-const pointer "data" - there is
    no restriction to accessing the elements pointed to by source->data.

    So your function can't change "source->data", but it /can/ change "source->data[sindex]".

    "const" does not pass through layers of pointers, it only applies to the
    first pointed-at layer.

    Does that help?



    /// image.c
    /// ...
    typedef struct {
    int w;
    int h;
    unsigned char channels;
    unsigned char *data;
    int err;
    } image_t;

    int image_copy(const image_t* source, const image_t* target, int xoffset, int yoffset) {
    register int sindex;
    register int tindex = 0;
    register int y1, x1;

    if (!source || !target)
    return -1;

    for (int y=0; y<target->h; y++) {
    for (int x=0; x<target->w; x++) {
    #if 1
    y1 = y+yoffset;
    x1 = x+xoffset;

    sindex = (y1 * source->w + x1) * 3;
    if (sindex > (source->w * source->h * 3))
    continue;

    // change value of element of const struct

    source->data[sindex+0] = target->data[tindex++];
    source->data[sindex+1] = target->data[tindex++];
    source->data[sindex+2] = target->data[tindex++];
    #endif
    }
    }

    return 0;
    }
    /// <eof>

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Ben Bacarisse@ben.usenet@bsb.me.uk to comp.std.c on Mon Sep 18 20:13:34 2023
    From Newsgroup: comp.std.c

    Denis Dos Santos Silva <denis@roo.com.br> writes:

    hi all!

    This would probably be better sent to comp.lang.c so I am setting the followup-to header accordingly. This group is mainly about the ISO C
    standard, though it's possible you are asking why the standard permits
    this.

    why this works? =)
    (from subject) why can change element of a const typed struct ?

    Short answer: you are not changing any member of the struct. The
    constness of the target of the pointer does transfer to other pointers
    in the struct. data is const, but data[x] is not.

    A detail... the struct is not const (well, it might be, but we can't
    tell from this code). The struct is being accessed via pointer whose
    target type is const. Now that would indeed require a diagnostic if the
    code tried to change any of the members, but it does not.

    /// image.c
    /// ...
    typedef struct {
    int w;
    int h;
    unsigned char channels;
    unsigned char *data;
    int err;
    } image_t;

    int image_copy(const image_t* source, const image_t* target, int
    xoffset, int yoffset) {
    ...
    source->data[sindex+0] = target->data[tindex++];
    source->data[sindex+1] = target->data[tindex++];
    source->data[sindex+2] = target->data[tindex++];
    ...
    }
    /// <eof>
    --
    Ben.
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Ben Bacarisse@ben.usenet@bsb.me.uk to comp.std.c on Mon Sep 18 20:58:52 2023
    From Newsgroup: comp.std.c

    David Brown <david.brown@hesbynett.no> writes:

    On 18/09/2023 17:49, Denis Dos Santos Silva wrote:
    hi all!
    why this works? =)

    Your image_t is const, but it has a non-const pointer "data" - there is no restriction to accessing the elements pointed to by source->data.

    I feel I must quibble because it can matter to someone learning C.

    When accessed via 'const image_t *source', data /is/ (treated as) const.
    data is a pointer, and the lvalue expression source->data is const
    qualified. To call it a "non-const pointer" is using a common
    shorthand, but one I've found is very confusing to beginners.

    We casually talk about "const pointers" and "non-const pointers" because
    we all know what we mean, but people learning C can get confused by what
    is and is not const-qualified. It's a handy shorthand because an actual
    'const pointer' is not seen so often:

    char *const endp = start + strlen(start);

    But we often see this

    const char *end = start + strlen(start);

    described as a const pointer even though changing the pointer is
    perfectly valid:

    end -= 1; // permitted because end is pointer that is not const

    So your function can't change "source->data",

    Right, because data is treated as a const pointer. Calling it a
    non-const pointer is potentially confusing. I know what you meant, but
    is it clear to everyone?

    but it /can/ change "source->data[sindex]".

    "const" does not pass through layers of pointers, it only applies to the first pointed-at layer.

    Your remark suggests that there is something special about one level of indirection, but there isn't.
    --
    Ben.
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From David Brown@david.brown@hesbynett.no to comp.std.c on Tue Sep 19 17:15:31 2023
    From Newsgroup: comp.std.c

    On 18/09/2023 21:58, Ben Bacarisse wrote:
    David Brown <david.brown@hesbynett.no> writes:

    On 18/09/2023 17:49, Denis Dos Santos Silva wrote:
    hi all!
    why this works? =)

    Your image_t is const, but it has a non-const pointer "data" - there is no >> restriction to accessing the elements pointed to by source->data.

    I feel I must quibble because it can matter to someone learning C.

    When accessed via 'const image_t *source', data /is/ (treated as) const.
    data is a pointer, and the lvalue expression source->data is const
    qualified. To call it a "non-const pointer" is using a common
    shorthand, but one I've found is very confusing to beginners.

    We casually talk about "const pointers" and "non-const pointers" because
    we all know what we mean, but people learning C can get confused by what
    is and is not const-qualified. It's a handy shorthand because an actual 'const pointer' is not seen so often:


    Those are very good points, and I am glad you gave a better and more
    accurate explanation than I did.



    --- Synchronet 3.20a-Linux NewsLink 1.114