469,342 Members | 5,438 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,342 developers. It's quick & easy.

Problem: assignment of read-only member

/* test.c */
#include <stdlib.h>

void f() {
struct X { const int x; };
struct X* myx = malloc(sizeof(struct X));
myx->x = 42;
}
/* end of test.c */

$ gcc-4.3 -c test.c
test.c: In function 'f':
test.c:7: error: assignment of read-only member 'x'

I would like x to be immutable once the struct is initialized. How do
I initialize it? I looked in the C FAQ but did not see anything that
addressed this specifically.

Or perhaps I'm going about this the wrong way?

Adam
Sep 14 '08 #1
16 16401
On Sun, 14 Sep 2008 10:33:13 -0700, aburry wrote:
/* test.c */
#include <stdlib.h>

void f() {
struct X { const int x; };
struct X* myx = malloc(sizeof(struct X));
myx->x = 42;
}
/* end of test.c */

$ gcc-4.3 -c test.c
test.c: In function 'f':
test.c:7: error: assignment of read-only member 'x'

I would like x to be immutable once the struct is initialized. How do I
initialize it? I looked in the C FAQ but did not see anything that
addressed this specifically.
The only way to initialise a dynamically allocated structure is by using
calloc, and if you do that, you can't choose an initialiser value.
Or perhaps I'm going about this the wrong way?
The problem is that there is not really a sane right way. You may be able
to use this:

struct X { const int x; };
struct X *myx = malloc(sizeof *myx);
struct X myx_value = { 42 };
memcpy(myx, &myx_value, sizeof *myx);

but it's ugly.
Sep 14 '08 #2
On Sep 14, 12:53 pm, Harald van Dk <tr*****@gmail.comwrote:
The problem is that there is not really a sane right way. You may be able
to use this:

struct X { const int x; };
struct X *myx = malloc(sizeof *myx);
struct X myx_value = { 42 };
memcpy(myx, &myx_value, sizeof *myx);

but it's ugly.
Isn't it possible that the compiler has chosen to store the 'x' member
in some kind of read-only memory, making the call to memcpy() unsafe?

Sebastian

Sep 14 '08 #3
On Sep 14, 10:33*pm, abu...@ieee.org wrote:
/* test.c */
#include <stdlib.h>

void f() {
struct X { const int x; };
struct X* myx = malloc(sizeof(struct X));
myx->x = 42;}

/* end of test.c */

$ gcc-4.3 -c test.c
test.c: In function 'f':
test.c:7: error: assignment of read-only member 'x'

I would like x to be immutable once the struct is initialized. How do
I initialize it? I looked in the C FAQ but did not see anything that
addressed this specifically.

Or perhaps I'm going about this the wrong way?

Adam
please go through following discussions
http://groups.google.com/group/comp....e80f24e3b00a40

--
vIpIn
Sep 14 '08 #4
On Sun, 14 Sep 2008 11:02:06 -0700, s0suk3 wrote:
On Sep 14, 12:53 pm, Harald van Dijk <tr*****@gmail.comwrote:
>The problem is that there is not really a sane right way. You may be
able to use this:

struct X { const int x; };
struct X *myx = malloc(sizeof *myx);
struct X myx_value = { 42 };
memcpy(myx, &myx_value, sizeof *myx);

but it's ugly.

Isn't it possible that the compiler has chosen to store the 'x' member
in some kind of read-only memory, making the call to memcpy() unsafe?
In general, yes, but here, no, that's not possible, since it's a member of
a dynamically allocated structure, and all bytes that malloc's result
points to must be writeable.
Sep 14 '08 #5
On Sun, 14 Sep 2008 10:33:13 -0700 (PDT), ab****@ieee.org wrote:
>/* test.c */
#include <stdlib.h>

void f() {
struct X { const int x; };
struct X* myx = malloc(sizeof(struct X));
myx->x = 42;
}
/* end of test.c */

$ gcc-4.3 -c test.c
test.c: In function 'f':
test.c:7: error: assignment of read-only member 'x'

I would like x to be immutable once the struct is initialized. How do
I initialize it? I looked in the C FAQ but did not see anything that
addressed this specifically.

Or perhaps I'm going about this the wrong way?
Since the language doesn't have a "write once" concept (other than
initialization as part of the definition), you have to fake it. One
approach that might do what you want is

struct X {int x;};
const struct X *myptr;
struct X *ptr_used_only_to_initialize_x = malloc(sizeof *myptr);
/* obvious error check goes here */
ptr_used_only_to_initialize_x->x = 42;
myptr = ptr_used_only_to_initialize_x;

and never use ptr_used_only_to_initialize_x again. You might even add
something like

#define ptr_used_only_to_initialize_x text to cause compile error

after the above code just to catch the any such use.

Naturally this will work only if all the members of the struct are to
be treated as const.
--
Remove del for email
Sep 14 '08 #6
On Sep 14, 8:33 pm, abu...@ieee.org wrote:
/* test.c */
#include <stdlib.h>

void f() {
struct X { const int x; };
struct X* myx = malloc(sizeof(struct X));
myx->x = 42;}

/* end of test.c */

$ gcc-4.3 -c test.c
test.c: In function 'f':
test.c:7: error: assignment of read-only member 'x'

I would like x to be immutable once the struct is initialized. How do
I initialize it? I looked in the C FAQ but did not see anything that
addressed this specifically.

Or perhaps I'm going about this the wrong way?
Well, why would you want a const member in a struct?
Here's a way to do this:

#include <stdlib.h>
#include <stddef.h>

struct x { const int i; }
struct x *p;
void *q;

p = q = malloc(sizeof *x)
if(p)
*(int *)((unsigned char *)q + offsetof(struct x, i)) = yourvalue;

free(p);

another more simple one:

*(int *)&p->i = yourvalue;

Sep 14 '08 #7
Thank you for the answers. I did search the group, but did not find
helpful thread vipin found. Here's a solved test case:

/* test.c */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int main(int argc, char* argv[] ) {
struct X { const int x; };
struct X* myx = malloc(sizeof *myx);
/* myx->x = 42; */ /* error: assignment of read-only member 'x'
*/

/* solution 1: */
#if 0
/* const initialization */
struct X myx_value = { 42 };
/* copy the const object */
memcpy(myx, &myx_value, sizeof *myx);
#endif

/* solution 2: */
#if 1
/* const cast */
*(int*)(&(myx->x)) = 42;
#endif

printf("%d\n", myx->x);
return 0;
}
/* test.c */

The const cast was what I wanted, but my attempts at coming up with an
lvalue failed.

Adam
Sep 14 '08 #8
On Sep 14, 9:56 pm, abu...@ieee.org wrote:
Thank you for the answers. I did search the group, but did not find
helpful thread vipin found. Here's a solved test case:

/* test.c */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int main(int argc, char* argv[] ) {
struct X { const int x; };
struct X* myx = malloc(sizeof *myx);
/* myx->x = 42; */ /* error: assignment of read-only member 'x'
*/

/* solution 1: */
#if 0
/* const initialization */
struct X myx_value = { 42 };
/* copy the const object */
memcpy(myx, &myx_value, sizeof *myx);
#endif
Well, if you don't like the temporary variable, you can do this in
C99:

memcpy(myx, (struct X []){ /* .i = */ 42 }, sizeof *myx);

Or a C89/C99 solution

{ struct X temp_ = { 42 }; memcpy(...); }

(*with* the braces)
Sep 14 '08 #9
vi******@gmail.com writes:
On Sep 14, 8:33 pm, abu...@ieee.org wrote:
>/* test.c */
#include <stdlib.h>

void f() {
struct X { const int x; };
struct X* myx = malloc(sizeof(struct X));
myx->x = 42;}

/* end of test.c */

$ gcc-4.3 -c test.c
test.c: In function 'f':
test.c:7: error: assignment of read-only member 'x'

I would like x to be immutable once the struct is initialized. How do
I initialize it? I looked in the C FAQ but did not see anything that
addressed this specifically.

Or perhaps I'm going about this the wrong way?

Well, why would you want a const member in a struct?
Why is that your concern? Maybe each struct member has a different const
member value? Did you think about that? His reasons are non of your
concern.
Here's a way to do this:

#include <stdlib.h>
#include <stddef.h>

struct x { const int i; }
struct x *p;
void *q;

p = q = malloc(sizeof *x)
if(p)
*(int *)((unsigned char *)q + offsetof(struct x, i)) = yourvalue;

free(p);

another more simple one:

*(int *)&p->i = yourvalue;
Did you not see the other posts pointing to the solution that you then
reposted? They were posted quite a while before your solution ...

http://groups.google.com/group/comp....e80f24e3b00a40

Interestingly enough you're spot on ....

The thread solution:

*(int*) ((char*)v + offsetof(struct thing, b)) = b;

Your solution:

*(int *)((unsigned char *)q + offsetof(struct x, i)) = yourvalue;

The reason I mention it is that I think its a travesty to keep
reinventing the wheel and posting the same thing when a good, well
explained solution is already out there.

Sep 14 '08 #10
On Sep 14, 5:01*pm, Richard<rgr...@gmail.comwrote:
vipps...@gmail.com writes:
On Sep 14, 8:33 pm, abu...@ieee.org wrote:
I would like x to be immutable once the struct is
initialized. How do I initialize it?
Well, why would you want a const member in a struct?

Why is that your concern? Maybe each struct member has a
different const member value? Did you think about that? His
reasons are non of your concern.
Unless he wanted to learn under what conditions someone would do a
thing like that? Did you think about that?

I actually do this kind of thing a lot. In C++ I can write:

class X {
public:
X(int val) : x(val) {}
private:
const int x;
};

And the compiler takes care of casting away the const during the
initialization. Similar to the following C example given elsewhere in
the thread:

struct X { const int x; } x = { 42 };

I like const members in situations where I want the object to be
parameterized at run-time, but where I do not expect/want the value to
change. I find that const members reduce the amount of thinking I have
to do. I can tell right away the member is not a variable I have to
really consider because it is a constant. Also, const allows me to say
what I mean; it is like extra documentation, only better.

In the particular case I was looking at today, I had an object that is
potentially shared. I want every object that has a reference to it to
know that their semantics are not going to change under their feet
(because the shared objects are const).

Hope that helps.
Did you not see the other posts pointing to the solution
that you then reposted? They were posted quite a while
before your solution ...

The reason I mention it is that I think its a travesty to
keep reinventing the wheel and posting the same thing when
a good, well explained solution is already out there.
Maybe his news server had not synced all the other responses yet. Did
you think about that?

The reason I mention it is that I think it's a travesty to chastise
someone for offering a helpful correct solution.

Adam
Sep 14 '08 #11
ab****@ieee.org writes:
On Sep 14, 5:01*pm, Richard<rgr...@gmail.comwrote:
>vipps...@gmail.com writes:
On Sep 14, 8:33 pm, abu...@ieee.org wrote:
I would like x to be immutable once the struct is
initialized. How do I initialize it?
Well, why would you want a const member in a struct?

Why is that your concern? Maybe each struct member has a
different const member value? Did you think about that? His
reasons are non of your concern.

Unless he wanted to learn under what conditions someone would do a
thing like that? Did you think about that?
Yes. I gave an example.

However the reason is immaterial IMO in this case.
>
I actually do this kind of thing a lot. In C++ I can write:

class X {
public:
X(int val) : x(val) {}
private:
const int x;
};

And the compiler takes care of casting away the const during the
initialization. Similar to the following C example given elsewhere in
the thread:

struct X { const int x; } x = { 42 };

I like const members in situations where I want the object to be
parameterized at run-time, but where I do not expect/want the value to
change.
Yes. As I said. I agree. Hence I said:

,----
| Maybe each struct member has a
| different const member value?
`----

I find that const members reduce the amount of thinking I have
to do. I can tell right away the member is not a variable I have to
really consider because it is a constant. Also, const allows me to say
what I mean; it is like extra documentation, only better.

In the particular case I was looking at today, I had an object that is
potentially shared. I want every object that has a reference to it to
know that their semantics are not going to change under their feet
(because the shared objects are const).

Hope that helps.
>Did you not see the other posts pointing to the solution
that you then reposted? They were posted quite a while
before your solution ...

The reason I mention it is that I think its a travesty to
keep reinventing the wheel and posting the same thing when
a good, well explained solution is already out there.

Maybe his news server had not synced all the other responses yet. Did
you think about that?
Maybe. It seems certain c.l.c members have really slow news servers. Strange.
>
The reason I mention it is that I think it's a travesty to chastise
someone for offering a helpful correct solution.

Adam
I did not chastise him.

I stand by my statement that repeated answers are not a good
thing. Frankly I have my suspicions but there you go. c.l.c has caused
me to be suspicious of peoples motives. Not a good thing I know and
possibly I need to learn to be more forgiving.

Sep 14 '08 #12
ab****@ieee.org writes:
void f() {
struct X { const int x; };
struct X* myx = malloc(sizeof(struct X));
myx->x = 42;
}
[...]
I would like x to be immutable once the struct is initialized. How do
I initialize it? I looked in the C FAQ but did not see anything that
addressed this specifically.
Are you sure that you really want to make the member immutable?
If it is good enough to make the whole structure immutable, you
can do something like this:

struct X { int x; };

const struct X *make_X(int value)
{
struct X *myx = malloc(sizeof *myx);
myx->x = value;
return myx;
}
--
char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa6 7f6aaa,0xaa9aa9f6,0x11f6},*p
=b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
Sep 15 '08 #13
In article <3c**********************************@2g2000hsn.go oglegroups.com>,
<ab****@ieee.orgwrote:
>struct X { const int x; };
struct X* myx = malloc(sizeof(struct X));
myx->x = 42;
What you want here is a struct with a member which is non-const until
you have set its value, and const thereafter. A fairly natural approach
would be to declare a modifiable version of the struct, and then
use a cast to get the non-modifiable version:

struct X { const int x; };

struct X *f(void)
{
struct modifiable_X { int x; };
struct modifiable_X *myx = malloc(sizeof(*myx));
myx->x = 42;
return (struct X *)myx;
}

What is the opinion of the group on the legality of this? Are the
two versions of the struct guaranteed to have the same representation?
Do the type-based aliasing rules make it undefined behaviour?

-- Richard
--
Please remember to mention me / in tapes you leave behind.
Sep 15 '08 #14
In article <06**********************************@z72g2000hsb. googlegroups.com>
<ab****@ieee.orgwrote:
>I like const members in situations where I want the object to be
parameterized at run-time, but where I do not expect/want the value to
change. ...
Unfortunately, as you have seen, const-qualified members are not
as well-supported in C as in other languages.
>In the particular case I was looking at today, I had an object that is
potentially shared. I want every object that has a reference to it to
know that their semantics are not going to change under their feet
(because the shared objects are const).
In the general case, "const"-qualification does not tell you that
the object will not actually change. For instance, consider:

#include <stdio.h>

void f(int *ip, const int *xp) {

printf("*xp is %d\n", *xp);
*ip = 42;
printf("*xp is %d\n", *xp);
}

You might expect this to print the same value every time, but
in fact, the line:

*ip = 42;

is allowed to change *xp to 42, and does so in:

int main(void) {
int x = 0;
f(&x, &x);
return 0;
}

To make the general case work, we need C99's "restrict" qualifier
as well: a "const int *restrict xp" cannot have both ip and xp
pointing to main()'s "x", in f().

(In this particular case, though, if "xp" had type "pointer to
struct X", where "struct X" has a const-qualified member C, the
compiler *is* allowed to assume that xp->C does not change at any
time. So it would do what you wanted, if you could do what you
wanted in the first place. This is mostly just another way to say
that specific cases can be less general than general cases.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: gmail (figure it out) http://web.torek.net/torek/index.html
Sep 15 '08 #15
In article <ga**********@pc-news.cogsci.ed.ac.uk>
Richard Tobin <ri*****@cogsci.ed.ac.ukwrote:
>What you want here is a struct with a member which is non-const until
you have set its value, and const thereafter. A fairly natural approach
would be to declare a modifiable version of the struct, and then
use a cast to get the non-modifiable version:

struct X { const int x; };

struct X *f(void)
{
struct modifiable_X { int x; };
struct modifiable_X *myx = malloc(sizeof(*myx));
myx->x = 42;
return (struct X *)myx;
}

What is the opinion of the group on the legality of this? Are the
two versions of the struct guaranteed to have the same representation?
Do the type-based aliasing rules make it undefined behaviour?
I think that there is enough wiggle room in the standard for an
"evil compiler" (DS9000 C) to cause it to fail, but I think that
it will actually work on all real implementations.

The main problem with this is that it is easy to goof up the
definition of the "struct modifiable_X", with negative consequences.
One can work around that by defining a macro for the contents of
"struct X":

/* this part probably goes in a header somewhere */
#define CONTENTS_OF_X \
int nonconst_int; \
char *nonconst_str; \
CONST int const_int; \
int another_int; \
double and_a_double;
#define CONST const

struct X {
CONTENTS_OF_X
};

/* while this part goes in x.c */
struct X new_x(... params ...) {
#undef CONST
#define CONST /*empty*/
struct modifiable_X { CONTENTS_OF_X };
... malloc and initialize and "return" as above ...
}

This has the advantage of continuing to work when the contents of
a "struct X" are modified, but the disadvantage of being quite
ugly ... almost as ugly as that other not-quite-C language. :-)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: gmail (figure it out) http://web.torek.net/torek/index.html
Sep 15 '08 #16
On Sep 15, 10:29*am, Chris Torek <nos...@torek.netwrote:
In article <066e34c7-6070-4386-bba8-3cbed74ea...@z72g2000hsb.googlegroups..com>

Unfortunately, as you have seen, const-qualified members are not
as well-supported in C as in other languages.
In the particular case I was looking at today, I had an object that is
potentially shared. I want every object that has a reference to it to
know that their semantics are not going to change under their feet
(because the shared objects are const).

In the general case, "const"-qualification does not tell you that
the object will not actually change. *For instance, consider:

* * #include <stdio.h>

* * void f(int *ip, const int *xp) {

* * * * printf("*xp is %d\n", *xp);
* * * * *ip = 42;
* * * * printf("*xp is %d\n", *xp);
* * }

You might expect this to print the same value every time, but
in fact, the line:

* * * * *ip = 42;

is allowed to change *xp to 42, and does so in:

* * int main(void) {
* * * * int x = 0;
* * * * f(&x, &x);
* * * * return 0;
* * }

To make the general case work, we need C99's "restrict" qualifier
as well: a "const int *restrict xp" cannot have both ip and xp
pointing to main()'s "x", in f().

(In this particular case, though, if "xp" had type "pointer to
struct X", where "struct X" has a const-qualified member C, the
compiler *is* allowed to assume that xp->C does not change at any
time. *So it would do what you wanted, if you could do what you
wanted in the first place. *This is mostly just another way to say
that specific cases can be less general than general cases.)
Your example works exactly as I would expect. If I wanted x to be
immutable, in main() I would write:

const int x = 0; /* note the const */

Now the call to f() generates a warning (in GCC 4.3).

The fact that *xp can be modified through ip in your example is not a
surprise at all. I would say you put your const in the wrong place.
That
is why I wanted the struct members to be const rather than just
using const pointers in the referers.

As an aside, I didn't want to make the entire struct const because I
may
add reference counting or something later.

But this is a bit off-topic now. And just to reiterate, the thread
that
vipin pointed out had the const cast syntax I was looking for, so the
original problem is solved. What I did in the end was create a
CONST_CAST
macro that I could use in my struct factory methods.

Adam
Sep 15 '08 #17

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by kliczko | last post: by
3 posts views Thread by collinm | last post: by
11 posts views Thread by Gagan | last post: by
1 post views Thread by Petterson Mikael | last post: by
1 post views Thread by Quinn | last post: by
9 posts views Thread by KWSW | last post: by
1 post views Thread by Sachin Garg | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by suresh191 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.