const members

S

S.Tobias

1. If I have a struct type which contains a const member:
struct mystruct
{
const int id;
int mutable;
};
does a definition
struct mystruct ms;
define an object `ms' which is *partly* const? Ie. the object `ms'
is not const as a whole, but modifying ms.id yields UB in all contexts?

2. Provided the answer to the above question is "yes" (ms.id is really
a const (sub)object), would the below code work:

struct mystruct_without_const
{
int id;
int mutable;
};

struct mystruct *new_mystruct(void)
{
struct mystruct_without_const *msp;
msp = malloc(sizeof *msp);
if (msp)
{
msp->id = /*generate id*/; /*well defined*/
msp->mutable = /*...*/;
}
return (struct mystruct*)msp;
}

(In above code I try to create a non-const struct object, initialize
supposed-to-be-const members in a well defined manner, and return a
pointer to the object where some members are "constified".)

Is there some kind of layout compatibility between mystruct and
mystruct_without_const?
 
R

Richard Bos

S.Tobias said:
1. If I have a struct type which contains a const member:
struct mystruct
{
const int id;
int mutable;
};
does a definition
struct mystruct ms;
define an object `ms' which is *partly* const? Ie. the object `ms'
is not const as a whole, but modifying ms.id yields UB in all contexts?

Yes. So unless you initialise it, ms.id contains garbage, can't be given
a reliable value, and is completely useless.
2. Provided the answer to the above question is "yes" (ms.id is really
a const (sub)object), would the below code work:

struct mystruct_without_const
{
int id;
int mutable;
};
Is there some kind of layout compatibility between mystruct and
mystruct_without_const?

Yes. 6.2.5#25:
# The qualified or unqualified versions of a type are distinct types
# that belong to the same type category and have the same representation
# and alignment requirements.39)
# 39) The same representation and alignment requirements are meant to
# imply interchangeability as arguments to functions, return values from
# functions, and members of unions.

I foresee some problems with your method, though; in particular, that
using malloc() is over-complicated, since you can assign (and therefore
use as a return value) structs, just as any other basic type.

Richard
 
L

Lawrence Kirby

1. If I have a struct type which contains a const member:
struct mystruct
{
const int id;
int mutable;
};
does a definition
struct mystruct ms;
define an object `ms' which is *partly* const?

There are 2 concepts to consider here, one is whether it is const i.e.
whether its type is const qualified. ms does not have a const qualified
type. The other is whether ms is "modifiable". A const object is
non-modifiable and because id has a non-modifiable member it is
non-modifiable as a whole, which means that things like

ms = another_mystruct;

result in undefined behaviour.
Ie. the object `ms'
is not const as a whole, but modifying ms.id yields UB in all contexts?

Yes modifying ms and ms.id result in UB where the latter is not a direct
constraint violation. Modifying ms.mutable is OK however.
2. Provided the answer to the above question is "yes" (ms.id is really
a const (sub)object), would the below code work:

struct mystruct_without_const
{
int id;
int mutable;
};

struct mystruct *new_mystruct(void)
{
struct mystruct_without_const *msp;
msp = malloc(sizeof *msp);
if (msp)
{
msp->id = /*generate id*/; /*well defined*/
msp->mutable = /*...*/;
}
return (struct mystruct*)msp;
}

(In above code I try to create a non-const struct object, initialize
supposed-to-be-const members in a well defined manner, and return a
pointer to the object where some members are "constified".)

Is there some kind of layout compatibility between mystruct and
mystruct_without_const?

Unfortunately struct mystruct_without_const and struct mystruct are
not compatible types, which pretty much means there are no requirements
for consistency of representation.

Lawrence
 
S

suman kar

Yes. So unless you initialise it, ms.id contains garbage, can't be given
a reliable value, and is completely useless.



Yes. 6.2.5#25:
# The qualified or unqualified versions of a type are distinct types
# that belong to the same type category and have the same representation
# and alignment requirements.39)
# 39) The same representation and alignment requirements are meant to
# imply interchangeability as arguments to functions, return values from
# functions, and members of unions.

I foresee some problems with your method, though; in particular, that
using malloc() is over-complicated, since you can assign (and therefore
use as a return value) structs, just as any other basic type.

Richard

Hi,

What I understand is:
1.`struct mystruct' and `mystruct_without_const' are distinct types
2.Now 6.2.5#25 says "The qualified or unqualified versions of a type..."
which implies (for me) something like

const struct mystruct something;
struct mystruct somethingElse;

have "The same representation and alignment requirements ..."
and so do:

const struct mystruct_without_const something2;
struct mystruct_without_const somethingElse2;

But that does not imply(for me)that the two structs have same alignment
requirements etc.

Am I wrong in my interpretation?Please explain.

Regards,
Suman.
 
R

Richard Bos

What I understand is:
1.`struct mystruct' and `mystruct_without_const' are distinct types
2.Now 6.2.5#25 says "The qualified or unqualified versions of a type..."
which implies (for me) something like

const struct mystruct something;
struct mystruct somethingElse;

have "The same representation and alignment requirements ..."
and so do:

const struct mystruct_without_const something2;
struct mystruct_without_const somethingElse2;

But that does not imply(for me)that the two structs have same alignment
requirements etc.

Erm... yes. That rule is for entire structs, not for structs with const
members. My fault; please ignore that post.

Richard
 
M

Michael Mair

suman said:
Hi,

What I understand is:
1.`struct mystruct' and `mystruct_without_const' are distinct types

Yep. One a non-modifiable, one a modifiable lvalue.
The types are not compatible.
2.Now 6.2.5#25 says "The qualified or unqualified versions of a type..."
which implies (for me) something like

const struct mystruct something;
struct mystruct somethingElse;

have "The same representation and alignment requirements ..."
and so do:

const struct mystruct_without_const something2;
struct mystruct_without_const somethingElse2;

It also implies
const int fixed;
int nonfixed;
to have the same representation and alignment requirements.
But that does not imply(for me)that the two structs have same alignment
requirements etc.

The structs are built up using the member types' alignment requirements.
As const int and int are treated the same, the structs should have the
same representation.


Cheers
Michael
 
L

Lawrence Kirby

On Tue, 16 Nov 2004 20:27:42 -0800, suman kar wrote:

....
Hi,

What I understand is:
1.`struct mystruct' and `mystruct_without_const' are distinct types

Specifically they are incompatible types.
2.Now 6.2.5#25 says "The qualified or unqualified versions of a type..."
which implies (for me) something like

const struct mystruct something;
struct mystruct somethingElse;

have "The same representation and alignment requirements ..."
and so do:

const struct mystruct_without_const something2;
struct mystruct_without_const somethingElse2;
Yes.


But that does not imply(for me)that the two structs have same alignment
requirements etc.

It would take a pathological implementation to represent the two
structures differently, but it is perfectly possible despite what the
footnote in the standard implies. Padding between structure members has
to provide suitable alignment for those members but isn't defined
solely in terms of that, other factors can be takien into consideration.
For example consider an array of 3 characters. That has to have 1 byte
alignment (or I suppose 3 in theory) requirements or else

char a[4][3];

wouldn't work. But a compiler might decide there are advantages to
aligning a structure member that is an array of 3 chars to 4 byte
boundaries.

Lawrence
 
S

S.Tobias

Richard Bos said:
I foresee some problems with your method, though; in particular, that
using malloc() is over-complicated,

I'm not sure I understand why you say "over-complicated"; think of
new_mystruct() as an allocator and constructor
(C++: mystruct *msp = new mystruct;).

I'll continue in reply to Lawrence Kirby.
 
S

S.Tobias

What I'm trying is to explore a possibility of creating a non-const
object and returning it to a client in such a form that it's partly
consted. Similarly to:
const char *get_const_buffer(void) /*return ptr to const-buffer*/
{
static char buffer[ENOUGH]; /*non-const object*/
return buffer;
}
but I want it only partly consted.

I'm thinking of having a pool of transparent struct type objects,
which could be reused. I forbid (well... at least make it harder)
the client to modify certain fields (`id') by designating them `const'.
But in order to reuse the object (to avoid free()/malloc()) the object
itself must be non-const, so that the library can regenerate `id' when
another object is requested.

(My aim would be achieved by making an opaque type and supplying
accessor functions (C++ way), but simplicity has its merits too and
I want to find out if "const" scheme would work.)

There are 2 concepts to consider here, one is whether it is const i.e.
whether its type is const qualified. ms does not have a const qualified
type. The other is whether ms is "modifiable". A const object is
non-modifiable and because id has a non-modifiable member it is
non-modifiable as a whole, which means that things like

Thanks for brining my attention to it.

A small nit-pick: you talk of "non-modifiable object". As I understand
it, objects may be const, but lvalues (expressions designating an object)
may be modifiable; eg. we may (try to) modify const object through
a modifiable lvalue (UB), or try to modyfy non-const object through
non-modifiable lvalue (constraint violation). Constness belongs to
objects and types, modifiability belongs to type system.
Please correct me if I'm wrong.
ms = another_mystruct;
result in undefined behaviour.

Or in diagnostics?

Yes modifying ms and ms.id result in UB where the latter is not a direct
constraint violation.

Could you please tell me how to derive it from the Standard; I think
it's not quite obvious. (I do believe you, it's just that I'm curious
and I want to learn.)


I think in my previous post I might have made an error in my thinking.
The buffer obtained from malloc() is not a const-object and I probably
don't need mystruct_without_const at all.

Please, have a look at my new code:

struct mystruct *new_mystruct(void)
{
struct mystruct *msp;
msp = malloc(sizeof *msp);
if (msp)
{
*(int*)& msp->id = /*generate id*/; /*well defined?*/
msp->mutable = /*...*/;
}
return msp;
}

Is that whole cast operation (simply meant to be in
C++ speak: const_cast<int&>) correct?

What effective type will the allocated buffer have after return?
 
L

Lawrence Kirby

On Thu, 18 Nov 2004 14:45:01 +0000, S.Tobias wrote:

....
I'm thinking of having a pool of transparent struct type objects, which
could be reused. I forbid (well... at least make it harder) the client
to modify certain fields (`id') by designating them `const'. But in
order to reuse the object (to avoid free()/malloc()) the object itself
must be non-const, so that the library can regenerate `id' when another
object is requested.

(My aim would be achieved by making an opaque type and supplying
accessor functions (C++ way), but simplicity has its merits too and I
want to find out if "const" scheme would work.)


Structly, no, but it would take a very unreasonable implementation to
break this, even the standard suggests that in footnotes.

IMHO this is the sort of thing you document the assumption and just go
ahead. Like assuming that EOF is distinct from the values returned by
getc() for all valid characters (although nobody I know of documents
that).
Thanks for brining my attention to it.

A small nit-pick: you talk of "non-modifiable object". As I understand
it, objects may be const, but lvalues (expressions designating an
object) may be modifiable; eg. we may (try to) modify const object
through a modifiable lvalue (UB), or try to modyfy non-const object
through non-modifiable lvalue (constraint violation). Constness belongs
to objects and types, modifiability belongs to type system. Please
correct me if I'm wrong.

You are correct that modifiable lvalue is a specific term defined by the
standard. I quoted my use of modifiable in eference to objects as it is my
own. It is reasonable to think of const defined objects and strin literal
objects as non-modifiable, the standard just says you get undefined
behaviour if you try to modify them.

const is just a type, i.e. compile time, concept. At runtime the issue is
whether something bad could happen if you try to write to an object, which
isn't the same as constness, although constness in the source code will
allow such badness.
Or in diagnostics?

Yes, you are correct - this requires a diagnostic. The LHS of an
assignment must be a modifiable lvalue and that can't be a structure type
with any (recursively) const members.
Could you please tell me how to derive it from the Standard; I think
it's not quite obvious. (I do believe you, it's just that I'm curious
and I want to learn.)

Since I was wrong that's tricky. :) For the diagnostic you have the
constraint of C99 6.5.16 and the definition of modifiable lvalue
6.3.2.1p1. FOr UB in other const cases the reference is C99 6.7.3p5.
I think in my previous post I might have made an error in my thinking.
The buffer obtained from malloc() is not a const-object and I probably
don't need mystruct_without_const at all.

Makes sense.
Please, have a look at my new code:

struct mystruct *new_mystruct(void)
{
struct mystruct *msp;
msp = malloc(sizeof *msp);
if (msp)
{
*(int*)& msp->id = /*generate id*/; /*well defined?*/

Looks good to me.
msp->mutable = /*...*/;
}
return msp;
}
}
Is that whole cast operation (simply meant to be in C++ speak:
const_cast<int&>) correct?

What effective type will the allocated buffer have after return?

AFAICS the caller code could modify the id member with
appropriate casting as you have done above and not onvoke UB. I can't see
that as a problem though. I think that's a that's significant here in
terms of "effective type".
 
S

S.Tobias

Unfortunately struct mystruct_without_const and struct mystruct are
not compatible types, which pretty much means there are no requirements
for consistency of representation.

Sorry to return here again, but I found this (it was there all the time
of course, but somehow I never noticed it :) ):

6.5 Expressions

[#7] An object shall have its stored value accessed only by
an lvalue expression that has one of the following types:63)

[ rephrased: ]
[ -- (qualified) (signed or unsigned version) compatible type ]

-- an aggregate or union type that includes one of the
aforementioned types among its members (including,
recursively, a member of a subaggregate or contained
union), or

I'm not sure I understand this correctly (it's rather unfortunately
formulated), but it seems that it supplies what I asked for.

What I think it says is that a struct (union, array) may be accessed
with a similar struct that differs by added qualification or
changed signdedness of its members. It means that such structs must be
layout-compatible.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,155
Messages
2,570,871
Members
47,401
Latest member
CliffGrime

Latest Threads

Top