Discussion:
why can change element of a const typed struct ?
(too old to reply)
Denis Dos Santos Silva
2023-09-18 15:49:12 UTC
Permalink
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>
David Brown
2023-09-18 18:29:06 UTC
Permalink
Post by Denis Dos Santos Silva
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?
Post by Denis Dos Santos Silva
/// 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>
Ben Bacarisse
2023-09-18 19:58:52 UTC
Permalink
Post by Denis Dos Santos Silva
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.
David Brown
2023-09-19 15:15:31 UTC
Permalink
Post by Ben Bacarisse
Post by Denis Dos Santos Silva
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
Those are very good points, and I am glad you gave a better and more
accurate explanation than I did.

Ben Bacarisse
2023-09-18 19:13:34 UTC
Permalink
Post by Denis Dos Santos Silva
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.
Post by Denis Dos Santos Silva
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.
Post by Denis Dos Santos Silva
/// 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) {
...
Post by Denis Dos Santos Silva
source->data[sindex+0] = target->data[tindex++];
source->data[sindex+1] = target->data[tindex++];
source->data[sindex+2] = target->data[tindex++];
...
Post by Denis Dos Santos Silva
}
/// <eof>
--
Ben.
Loading...