Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #15003 > unrolled thread
| Started by | pozz <pozzugno@gmail.com> |
|---|---|
| First post | 2011-12-26 20:13 +0100 |
| Last post | 2011-12-27 03:16 +0000 |
| Articles | 7 — 5 participants |
Back to article view | Back to comp.lang.c
const fields in a struct pozz <pozzugno@gmail.com> - 2011-12-26 20:13 +0100
Re: const fields in a struct Seebs <usenet-nospam@seebs.net> - 2011-12-26 20:26 +0000
Re: const fields in a struct Philip Lantz <prl@canterey.us> - 2011-12-26 14:21 -0800
Re: const fields in a struct Philip Lantz <prl@canterey.us> - 2011-12-26 14:22 -0800
Re: const fields in a struct Ben Bacarisse <ben.usenet@bsb.me.uk> - 2011-12-27 00:15 +0000
Re: const fields in a struct pozz <pozzugno@gmail.com> - 2011-12-28 01:35 -0800
Re: const fields in a struct Nobody <nobody@nowhere.com> - 2011-12-27 03:16 +0000
| From | pozz <pozzugno@gmail.com> |
|---|---|
| Date | 2011-12-26 20:13 +0100 |
| Subject | const fields in a struct |
| Message-ID | <jdah0l$las$1@nnrp.ngi.it> |
I defined a struct with several members. Just an example:
typedef struct {
unsigned int id;
char *text;
int font_id;
int visible;
} LABEL;
In my application I have many const LABELs (their members value don't
change during the execution) that I declare in this way:
const LABEL lbl1 = { 0x0001U, "Const label", 1, 1};
Here defining lbl1 with const keywork has two advantages: my embedded C
compiler/linker put it in the non-volatile big Flash memory, so saving
the precious small RAM memory and giving the compiler the instrument to
advice me (with a warning) if I wrongly try to modify the struct members
at run-time.
In addition to completely const labels, I have also 10-20 labels with
only visible member variable at run-time. My goal is to put also these
labels in Flash memory, so I changed LABEL definition in this way:
typedef struct {
unsigned int id;
char *text;
int font_id;
int *visible;
} LABEL;
visible now is a pointer that is always const, but the value pointed
could change at run-time. So I tried this:
const int visible_true = 1;
const int visible_false = 0;
int visible_lbl2 = 1;
const LABEL lbl1 = { 0x0001U, "Const label", 1, &visible_true};
const LABEL lbl2 = { 0x0001U, "Pseudo-const label", 1, &visible_lbl2};
Now the compiler emits a warning for lbl1 declaration, because I assign
the pointer of a const int (&visible_true) to an int.
I could change LABEL definition in the following way:
typedef struct {
unsigned int id;
char *text;
int font_id;
const int *visible;
} LABEL;
so avoiding that kind of warning... but, is it the correct way to solve
my problem? What if I will have with a completely "non-const" label
when I want to change the visible status? I won't be able to do
something like:
int visible_lbl3;
LABEL lbl3 = { 0x0001U, "Non-const label", 1, &visible_lbl3};
*lbl3.visible = 0;
Any suggestions?
[toc] | [next] | [standalone]
| From | Seebs <usenet-nospam@seebs.net> |
|---|---|
| Date | 2011-12-26 20:26 +0000 |
| Message-ID | <slrnjfhm04.gcg.usenet-nospam@guild.seebs.net> |
| In reply to | #15003 |
On 2011-12-26, pozz <pozzugno@gmail.com> wrote:
> visible now is a pointer that is always const, but the value pointed
> could change at run-time. So I tried this:
> const int visible_true = 1;
> const int visible_false = 0;
> int visible_lbl2 = 1;
> const LABEL lbl1 = { 0x0001U, "Const label", 1, &visible_true};
> const LABEL lbl2 = { 0x0001U, "Pseudo-const label", 1, &visible_lbl2};
> Now the compiler emits a warning for lbl1 declaration, because I assign
> the pointer of a const int (&visible_true) to an int.
You probably mean "int *const". "const int *" is a pointer to a const int,
you want a const pointer to an int.
-s
--
Copyright 2011, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
I am not speaking for my employer, although they do rent some of my opinions.
[toc] | [prev] | [next] | [standalone]
| From | Philip Lantz <prl@canterey.us> |
|---|---|
| Date | 2011-12-26 14:21 -0800 |
| Message-ID | <MPG.2962935ec274fc89989681@news.eternal-september.org> |
| In reply to | #15006 |
Seebs wrote:
>
> On 2011-12-26, pozz <pozzugno@gmail.com> wrote:
> > visible now is a pointer that is always const, but the value pointed
> > could change at run-time. So I tried this:
>
> > const int visible_true = 1;
> > const int visible_false = 0;
> > int visible_lbl2 = 1;
> > const LABEL lbl1 = { 0x0001U, "Const label", 1, &visible_true};
> > const LABEL lbl2 = { 0x0001U, "Pseudo-const label", 1, &visible_lbl2};
>
> > Now the compiler emits a warning for lbl1 declaration, because I assign
> > the pointer of a const int (&visible_true) to an int.
>
> You probably mean "int *const". "const int *" is a pointer to a const int,
> you want a const pointer to an int.
No, he doesn't need a const on the structure member, because he is
defining the entire structure as const. However, he also doesn't want a
pointer to const, because he wants to be able to change the value
pointed to. My other post has additional comments.
Philip
[toc] | [prev] | [next] | [standalone]
| From | Philip Lantz <prl@canterey.us> |
|---|---|
| Date | 2011-12-26 14:22 -0800 |
| Message-ID | <MPG.2962937881d37896989682@news.eternal-september.org> |
| In reply to | #15003 |
pozz wrote:
>
> I defined a struct with several members. Just an example:
>
> typedef struct {
> unsigned int id;
> char *text;
> int font_id;
> int visible;
> } LABEL;
>
> In my application I have many const LABELs (their members value don't
> change during the execution) that I declare in this way:
>
> const LABEL lbl1 = { 0x0001U, "Const label", 1, 1};
>
> Here defining lbl1 with const keywork has two advantages: my embedded C
> compiler/linker put it in the non-volatile big Flash memory, so saving
> the precious small RAM memory and giving the compiler the instrument to
> advice me (with a warning) if I wrongly try to modify the struct members
> at run-time.
>
> In addition to completely const labels, I have also 10-20 labels with
> only visible member variable at run-time. My goal is to put also these
> labels in Flash memory, so I changed LABEL definition in this way:
>
> typedef struct {
> unsigned int id;
> char *text;
> int font_id;
> int *visible;
> } LABEL;
>
> visible now is a pointer that is always const, but the value pointed
> could change at run-time. So I tried this:
>
> const int visible_true = 1;
> const int visible_false = 0;
> int visible_lbl2 = 1;
> const LABEL lbl1 = { 0x0001U, "Const label", 1, &visible_true};
> const LABEL lbl2 = { 0x0001U, "Pseudo-const label", 1, &visible_lbl2};
>
> Now the compiler emits a warning for lbl1 declaration, because I assign
> the pointer of a const int (&visible_true) to an int.
>
> I could change LABEL definition in the following way:
>
> typedef struct {
> unsigned int id;
> char *text;
> int font_id;
> const int *visible;
> } LABEL;
>
> so avoiding that kind of warning... but, is it the correct way to solve
> my problem? What if I will have with a completely "non-const" label
> when I want to change the visible status? I won't be able to do
> something like:
>
> int visible_lbl3;
> LABEL lbl3 = { 0x0001U, "Non-const label", 1, &visible_lbl3};
> *lbl3.visible = 0;
>
> Any suggestions?
You don't want a pointer to const, because you want to be able to change
the value pointed to. I think the best solution is to make visible_true
and visible_false not const, even though you know that they aren't
supposed to change.
An alternative is to use a cast in the initialization:
const LABEL lbl1 = { 0x0001U, "Const label", 1, (int *)&visible_true};
This is legal and safe, as long as you don't try to change
*lbl1.visible; if you do, it would be undefined behavior.
Another alternative is to use const int *visible, as you suggested and
use a cast in the final line:
*(int *)lbl3.visible = 0;
This is also legal and safe, as long as you *know* that lbl3.visible
actually points to a non-const object. If it actually points to a const
object, such as visible_true, it would again be undefined behavior.
From a program-level point of view, these are all essentially
equivalent--obviously, you don't want to change visible_true to 0, so
whether it would be undefined behavior or not is irrelevant; the program
would be broken either way. Since the compiler can't know which of your
LABELs point to const visible objects and which don't, you (the
programmer) have to keep track of that and ensure that you don't change
*lbl.visible in those cases when you mustn't.
Philip
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2011-12-27 00:15 +0000 |
| Message-ID | <0.1c014ba0f0c6ce55877b.20111227001537GMT.87vcp2euom.fsf@bsb.me.uk> |
| In reply to | #15003 |
pozz <pozzugno@gmail.com> writes:
> I defined a struct with several members. Just an example:
>
> typedef struct {
> unsigned int id;
> char *text;
> int font_id;
> int visible;
> } LABEL;
>
> In my application I have many const LABELs (their members value don't
> change during the execution) that I declare in this way:
>
> const LABEL lbl1 = { 0x0001U, "Const label", 1, 1};
>
> Here defining lbl1 with const keywork has two advantages: my embedded
> C compiler/linker put it in the non-volatile big Flash memory, so
> saving the precious small RAM memory and giving the compiler the
> instrument to advice me (with a warning) if I wrongly try to modify
> the struct members at run-time.
>
> In addition to completely const labels, I have also 10-20 labels with
> only visible member variable at run-time. My goal is to put also
> these labels in Flash memory, so I changed LABEL definition in this
> way:
>
> typedef struct {
> unsigned int id;
> char *text;
> int font_id;
> int *visible;
> } LABEL;
This looks like the right start. You will make these LABELs const (so
they go into flash memory), but you will change the int pointed to by
visible during run-time. You won't be able to change what visible
points to because the whole structure instance will be declared const.
> visible now is a pointer that is always const, but the value pointed
> could change at run-time. So I tried this:
>
> const int visible_true = 1;
> const int visible_false = 0;
> int visible_lbl2 = 1;
> const LABEL lbl1 = { 0x0001U, "Const label", 1, &visible_true};
> const LABEL lbl2 = { 0x0001U, "Pseudo-const label", 1, &visible_lbl2};
>
> Now the compiler emits a warning for lbl1 declaration, because I
> assign the pointer of a const int (&visible_true) to an int.
Well, that must be a paraphrase, yes? The error should be about
initialising a pointer to an int with the address of a const int.
> I could change LABEL definition in the following way:
>
> typedef struct {
> unsigned int id;
> char *text;
> int font_id;
> const int *visible;
> } LABEL;
>
> so avoiding that kind of warning... but, is it the correct way to
> solve my problem? What if I will have with a completely "non-const"
> label when I want to change the visible status? I won't be able to do
> something like:
>
> int visible_lbl3;
> LABEL lbl3 = { 0x0001U, "Non-const label", 1, &visible_lbl3};
> *lbl3.visible = 0;
This is the right way to go, but without the const int *visible. I'd
use a non-const int for each instance of LABEL. Those LABELs that you
declare const still have alterable data via the visible pointer, and
those not declared const can have all members altered:
typedef struct {
unsigned int id;
char *text;
int font_id;
int *visible;
} LABEL;
int visible_lbl1 = 1;
int visible_lbl2 = 2;
const LABEL lbl1 = { 0x0001U, "Const label", 1, &visible_lbl1};
LABEL lbl2 = { 0x0001U, "Pseudo-const label", 1, &visible_lbl2};
This is not perfect, of course. For one thing, even those LABELs that
must be 100% constant (like lbl1) can have *lbl1.visible changed. I
don't think there is a good solution to that.
Another problem is that you might accidentally change lbl2.visible to
point somewhere else. If this is a danger then you need this:
typedef struct {
unsigned int id;
char *text;
int font_id;
int *const visible;
} LABEL;
so that once initialised, visible, can't be altered even in non-const
LABELs like lbl2.
Finally, all of the LABELs will use one int's worth of precious RAM. If
this RAM usage is too great a problem then, you might consider a small
"lie" to the compiler. You can force the compiler to accept a pointer
to a const int like this:
const int visible_lbl1 = 1;
const LABEL lbl1 = { 0x0001U, "Const label", 1, (int *)&visible_lbl1};
but you must now be more careful. Where as, before, changing
*lbl1.visible was probably an error in the program logic, it is now an
undefined operation in C. I'd only do this as a last resort.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | pozz <pozzugno@gmail.com> |
|---|---|
| Date | 2011-12-28 01:35 -0800 |
| Message-ID | <53d06434-fcab-4312-ac1d-2a828b5e2dd1@p13g2000yqd.googlegroups.com> |
| In reply to | #15013 |
On 27 Dic, 01:15, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:
> pozz <pozzu...@gmail.com> writes:
> > [...]
> > visible now is a pointer that is always const, but the value pointed
> > could change at run-time. So I tried this:
>
> > const int visible_true = 1;
> > const int visible_false = 0;
> > int visible_lbl2 = 1;
> > const LABEL lbl1 = { 0x0001U, "Const label", 1, &visible_true};
> > const LABEL lbl2 = { 0x0001U, "Pseudo-const label", 1, &visible_lbl2};
>
> > Now the compiler emits a warning for lbl1 declaration, because I
> > assign the pointer of a const int (&visible_true) to an int.
>
> Well, that must be a paraphrase, yes? The error should be about
> initialising a pointer to an int with the address of a const int.
Yes, you're right.
> This is the right way to go, but without the const int *visible. I'd
> use a non-const int for each instance of LABEL. Those LABELs that you
> declare const still have alterable data via the visible pointer, and
> those not declared const can have all members altered:
>
> typedef struct {
> unsigned int id;
> char *text;
> int font_id;
> int *visible;
> } LABEL;
>
> int visible_lbl1 = 1;
> int visible_lbl2 = 2;
> const LABEL lbl1 = { 0x0001U, "Const label", 1, &visible_lbl1};
> LABEL lbl2 = { 0x0001U, "Pseudo-const label", 1, &visible_lbl2};
>
> This is not perfect, of course. For one thing, even those LABELs that
> must be 100% constant (like lbl1) can have *lbl1.visible changed. I
> don't think there is a good solution to that.
Thank you for your suggestions.
Anyway I think the C language is slightly poor to manage these kinds
of things. My need is nothing special: I want declare a generic
struct with members that could change at run-time (for example,
showing or hiding a label), but at the same time use constant values
when I know they won't ever change.
[toc] | [prev] | [next] | [standalone]
| From | Nobody <nobody@nowhere.com> |
|---|---|
| Date | 2011-12-27 03:16 +0000 |
| Message-ID | <pan.2011.12.27.03.16.05.263000@nowhere.com> |
| In reply to | #15003 |
On Mon, 26 Dec 2011 20:13:27 +0100, pozz wrote:
> but, is it the correct way to solve my problem?
Yes. With "int *visible", the compiler won't complain if you do:
*lbl1.visible = 0;
even though that would (attempt to) modify visible_true.
> What if I will have with a completely "non-const" label
> when I want to change the visible status? I won't be able to do
> something like:
>
> int visible_lbl3;
> LABEL lbl3 = { 0x0001U, "Non-const label", 1, &visible_lbl3};
> *lbl3.visible = 0;
Correct; you'd have to change visible_lbl3 directly rather than through
the pointer.
If you're using C99, you could make the visible field a union, i.e.:
union {
const int *constant;
int *mutable;
} visible;
But then you'd need a tag field to indicate which of the two members was
used for a particular label. And that won't work with C89, which only
allows you to initialise the first element of a union.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web