Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #15003 > unrolled thread

const fields in a struct

Started bypozz <pozzugno@gmail.com>
First post2011-12-26 20:13 +0100
Last post2011-12-27 03:16 +0000
Articles 7 — 5 participants

Back to article view | Back to comp.lang.c


Contents

  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

#15003 — const fields in a struct

Frompozz <pozzugno@gmail.com>
Date2011-12-26 20:13 +0100
Subjectconst 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]


#15006

FromSeebs <usenet-nospam@seebs.net>
Date2011-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]


#15010

FromPhilip Lantz <prl@canterey.us>
Date2011-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]


#15011

FromPhilip Lantz <prl@canterey.us>
Date2011-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]


#15013

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2011-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]


#15078

Frompozz <pozzugno@gmail.com>
Date2011-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]


#15016

FromNobody <nobody@nowhere.com>
Date2011-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