A more verbose discussion of const and conversions... (part 2)

D

d3x0xr

Heh, spelled out in black and white even :) Const is useles...

do NOT follow the path of considering any data consatant, because in
time, you will have references to it that C does not handle, and you'll
be left with just noisy compiler warnings and confusion.

if you start a project with all char *, and char ** and even char ***,
if you begin at the low level weeding out references of 'passing const
char * to char * ( such as myfunction ( char * blah ); yourfunction(
void ) { myfunction( "blasdfakljsdf" ); } )

And I guarantee that the declared references to the data are ....

7.1.4 Use of library functions
1 Each of the following statements applies unless explicitly stated
otherwise in the detailed descriptions that follow: If an argument to a
function has an invalid value (such as a value outside the domain of the
function, or a pointer outside the address space of the program,
or a null pointer, or a <BOLD>pointer to non-modifiable storage when the
corresponding parameter is not const-qualified)</BOLD>or a type (after
promotion) not expected by a function with variable number of arguments,
the behavior is undefined.

So I have decided I want to stick to defined behaviors, and allow users
the lattitutude to do what they want.





( this is mostly just notes and pulling relavent chunks, but then
reading and comprehending are two different things, if const is
literally implemented, then there are still inconsitancies)

-----

typedef const char a;
typedef const a * b; // Error! E1060: Invalid type

?
// there was a portion of the standard that says no matter how many
times the qualifier appears for a type, that it makes no difference.


-----

char const * const * gvar;
char const * cvar;

gvar = &cvar; // OK: 'char const **' conversion to 'char const *const
*'


Following the standard, why does the above not fail due to
6.7.5.1.2(below)?


-----

Full test results are at the end... I don't get it... somehow I think
that there's a special case somewhere that isn't right, and/or should be
extended....

------------------------------------------------------------
------------------------------------------------------------
Okay, really, I give up. I fixed everything so it doesn't fail
compiling with C++, for which warnings became errors. Certainly one
direction is okay and deserves not a warning.

I was really just cleaning warnings, and find I keep changing this
definitino of variable, and now, nothing is happy cause at one point or
another there are edge conditions where const-qualified code meets
nonqualified code, and it's always ugly, except in a couple simple
cases, which are 'byproducts' of .. [6.3.2.1-2], or [6.5.4.4] I
guess...







6.5.16.1 Simple assignment
..1 One of the following shall hold: [ 93) The asymmetric appearance of
these constraints with respect to type qualifiers is due to the
conversion (specified in 6.3.2.1[.2]) that changes lvalues to ''the
value of the expression'' which removes any type qualifiers from the
type category of the expression. ]

- the left operand has qualified or unqualified arithmetic type and the
right has arithmetic type;
- the left operand has a qualified or unqualified version of a structure
or union type compatible with the type of the right;
- both operands are pointers to qualified or unqualified versions of
compatible types, and the type pointed to by the left has all the
qualifiers of the type pointed to by the right;
- one operand is a pointer to an object or incomplete type and the other
is a pointer to a qualified or unqualified version of void, and the type
pointed to by the left has all the qualifiers of the type pointed to by
the right;
- the left operand is a pointer and the right is a null pointer
constant; or
- the left operand has type _Bool and the right is a pointer.

..6 EXAMPLE 3 Consider the fragment:
const char **cpp;
char *p;
const char c = 'A';
cpp = &p; // constraint violation
*cpp = &c; // valid
*p = 0; // valid
The first assignment is unsafe because it would allow the following
valid code to attempt to change the value of the const object c.


Okay and even the other fragment I wrote just now about storing another
const char * in place of an argument results in perhaps a rom data point
that the subsequent code could expect to modify, but cannot.


But if we modify the above frament slightly

const char *const*cpp; // <-- add additional const.
char *p;
const char c = 'A';
cpp = &p; // constraint violation
*cpp = &c; // valid //<-- invalid, cannot modify const *ERROR*
*p = 0; // valid //

Also stops the replacement of (char *) elements with (const char *)
which may indeed be read only.


const char *const*cpp; // <-- add additional const.
char * *p;
cpp=p; // without


6.3.2 Other operands
6.3.2.1 Lvalues, arrays, and function designators
1 Anlvalue is an expression with an object type or an incomplete type
other than void;53) if an lvalue does not designate an object when it is
evaluated, the behavior is undefined. When an object is said to have a
particular type, the type is specified by the lvalue used to
designate the object. A modifiable lvalue is an lvalue that does not
have array type, does not have an incomplete type, does not have a
const-qualified type, and if it is a structure or union, does not have
any member (including, recursively, any member or element of all
contained aggregates or unions) with a const-qualified type.

2 Except when it is the operand of the sizeof operator, the unary &
operator, the ++ operator, the -- operator, or the left operand of the .
operator or an assignment operator, an lvalue that does not have array
type is converted to the value stored in the designated object (and is
no longer an lvalue). If the lvalue has qualified type, the value has
the unqualified version of the type of the lvalue; otherwise, the value
has the type of the lvalue. If the lvalue has an incomplete type and
does not have array type, the behavior is undefined.

---
My notes so if none of these...

sizeof(lvalue)
&lvalue
lvalue++
lvalue--
lvelue=
lvalue[]
lvalue.

then copy data within lvalue, and make it a value, which is not an
lvalue, that is not const.)
the value result is non qualified.

6.5.4.4
note 85) A cast does not yield an lvalue. Thus, a cast to a qualified
type has the same effect as a cast to the unqualified version of the
type.



----------------------

Back research As I read I began to wonder if they hadn't defined a
smaller box for themselves...

6.7.5.1 Pointer declarators
Semantics
1 If, in the declaration ''T D1'', D1 has the form
* type-qualifier-listopt D
and the type specified for ident in the declaration ''T D'' is
''derived-declarator-type-list
T'', then the type specified for ident is ''derived-declarator-type-list
type-qualifier-list
pointer to T''. For each type qualifier in the list, ident is a
so-qualified pointer.


[6.7.5.1.2] For two pointer types to be compatible, both shall be
identically qualified and both shall
be pointers to compatible types.

!!!!!!!!!!!!!!

that(6.7.5.1.2) would mean

int **pxia;·
int * const *pxib;·

pxib=pxia;·

should also be invalid, but it's not a warning.



int * * * * * * * zpxia;·
int * const * * * const * const * * zpxib;·


zpxib=zpxia;·

Is invalid however....


6.7.3.9 For two qualified types to be compatible, both shall have the
identically qualified version of a compatible type; the order of type
qualifiers within a list of specifiers or qualifiers does not affect the
specified type.


------
verbatum check for types, both with bare type and progressive
derivations<?> of type.

void junkx( void )
{
const char aconst;
char avar;
char * const bconst;
char *bvar;

char const * const cconst;
char const * cvar;

char * * const dconst;
char const * * const econst;
char * const * const fconst;
char const * const * const gconst;

char * *dvar;
char const * * evar;
char * const *fvar;
char const * const * gvar;

char * * * hvar;
char const * * * ivar;
char * const * *jvar;
char const * const * * kvar;
char * * const * lvar;
char const * * const * mvar;
char * const * const *nvar;
char const * const * const * ovar;

//bconst = &aconst;
//bconst = &avar;
bvar = &aconst;
bvar = &avar; // invalid char const * -> char *

bvar = cconst; // invalid char const * -> char *
bvar = cvar; // invalid char const * -> char *

cvar = &aconst;
cvar = &avar;

cvar = bconst;
cvar = bvar;

dvar = &bvar; // OK: 'char **' -> 'char **'
dvar = &bconst; // 'char *const *' -> 'char **'
dvar = &cvar; // 'char const **' -> 'char **'
dvar = &cconst; // 'char const *const *' -> 'char **'

evar = &bvar; // 'char **' -> 'char const **'
evar = &bconst; // 'char *const *' -> 'char const **'
evar = &cvar; // OK: 'char const **' -> 'char const **'
evar = &cconst; // 'char const *const *' -> 'char const **'

fvar = &bvar; // OK: 'char const **' -> 'char *const *'
fvar = &bconst; // OK: 'char *const *' -> 'char *const *'
fvar = &cvar; // 'char const **' -> 'char *const *'
fvar = &cconst; // 'char const *const *' -> 'char *const *'

gvar = &bvar; // 'char const **' -> 'char const *const *'
gvar = &bconst; // 'char *const *' -> 'char const *const *'
gvar = &cvar; // OK: 'char const **' -> 'char const *const *'
gvar = &cconst; // OK: 'char const *const *' -> 'char const *const
*'


hvar = &dvar; // OK: 'char ***' -> 'char ***'
hvar = &dconst; // 'char **const *' -> 'char ***'
hvar = &evar; // 'char const ***' -> 'char ***'
hvar = &econst; // 'char const **const *' -> 'char ***'
hvar = &fvar; // 'char *const **' -> 'char ***'
hvar = &fconst; // 'char const **const *' -> 'char ***'
hvar = &gvar; // 'char const *const **' -> 'char ***'
hvar = &gconst; // 'char const *const *const *' -> 'char ***'

ivar = &dvar; // 'char ***' -> 'char const ***'
ivar = &dconst; // 'char **const *' -> 'char const ***'
ivar = &evar; // OK:'char const ***' -> 'char const ***'
ivar = &econst; // 'char const **const *' -> 'char const ***'
ivar = &fvar; // 'char *const **' -> 'char const ***'
ivar = &fconst; // 'char const **const *' -> 'char const ***'
ivar = &gvar; // 'char const *const **' -> 'char const ***'
ivar = &gconst; // 'char const *const *const *' -> 'char const ***'

jvar = &dvar; // 'char ***' -> 'char *const **'
jvar = &dconst; // 'char **const *' -> 'char *const **'
jvar = &evar; // 'char const ***' -> 'char *const **'
jvar = &econst; // 'char const **const *' -> 'char *const **'
jvar = &fvar; // OK'char *const **' -> 'char *const **'
jvar = &fconst; // 'char const **const *' -> 'char *const **'
jvar = &gvar; // 'char const *const **' -> 'char *const **'
jvar = &gconst; // 'char const *const *const *' -> 'char *const **'

kvar = &dvar; // 'char ***' -> 'char const * const **'
kvar = &dconst; // 'char **const *' -> 'char const * const **'
kvar = &evar; // 'char const ***' -> 'char const * const **'
kvar = &econst; // 'char const **const *' -> 'char const * const
**'
kvar = &fvar; // 'char *const **' -> 'char const * const **'
kvar = &fconst; // 'char const **const *' -> 'char const * const
**'
kvar = &gvar; // OK: 'char const *const **' -> 'char const *
const **'
kvar = &gconst; // 'char const *const *const *' -> 'char const *
const **'



}


typedef char a;

typedef char *b;
typedef a *b_;

typedef const char *c;
typedef const a *c_;


typedef char **d;
typedef b_ *d_;
typedef char const **e;
typedef c_ *e_;
typedef char *const *f;
typedef const b_ *f_;
typedef char const *const *g;
typedef const c_ *g_;


typedef char ***h;
typedef d_ *h_;
typedef char const ***i;
typedef e_ *i_;
typedef char *const **j;
typedef f_ *j_;
typedef char const *const **k;
typedef g_ *k_;
typedef char **const *l;
typedef const d_ *l_;
typedef char const **const *m;
typedef const e_ *m_;
typedef char *const *const *n;
typedef const f_ *n_;
typedef char const *const *const *o;
typedef const g_ *o_;

void junky( void )
{
const a aconst;
a avar;

const b bconst;
b bvar;
const c cconst;
c cvar;

const b_ _bconst;
b_ _bvar;
const c_ _cconst;
c_ _cvar;

const d dconst;
const e econst;
const f fconst;
const g gconst;

d_ dvar;
e_ evar;
f_ fvar;
g_ gvar;

h_ hvar;
i_ ivar;
j_ jvar;
k_ kvar;
l_ lvar;
m_ mvar;
n_ nvar;
o_ ovar;

bvar=_bvar;
_bvar=bvar;
bvar=_cvar; // char const * -> char *
_bvar=cvar; // char const * -> char *
_cvar=cvar;
cvar=_cvar;
_cvar=bvar;
cvar=_bvar;


//bconst = &aconst;
//bconst = &avar;
bvar = &aconst; // invalid 'char const *' ->'char*'
bvar = &avar; // invalid char const * -> char *

bvar = cconst; // invalid char const * -> char *
bvar = cvar; // invalid char const * -> char *

cvar = &aconst; // okay
cvar = &avar; // okay

cvar = bconst; // okay
cvar = bvar; // okay

dvar = &bvar; // OK: 'char **' -> 'char **'
dvar = &bconst; // 'char *const *' -> 'char **'
dvar = &cvar; // 'char const **' -> 'char **'
dvar = &cconst; // 'char const *const *' -> 'char **'

evar = &bvar; // 'char **' -> 'char const **'
evar = &bconst; // 'char *const *' -> 'char const **'
evar = &cvar; // OK: 'char const **' -> 'char const **'
evar = &cconst; // 'char const *const *' -> 'char const **'

fvar = &bvar; // OK: 'char const **' -> 'char *const *'
fvar = &bconst; // OK: 'char *const *' -> 'char *const *'
fvar = &cvar; // 'char const **' -> 'char *const *'
fvar = &cconst; // 'char const *const *' -> 'char *const *'

gvar = &bvar; // 'char const **' -> 'char const *const *'
gvar = &bconst; // 'char *const *' -> 'char const *const *'
gvar = &cvar; // OK: 'char const **' -> 'char const *const *'
gvar = &cconst; // OK: 'char const *const *' -> 'char const *const
*'


hvar = &dvar; // OK: 'char ***' -> 'char ***'
hvar = &dconst; // 'char **const *' -> 'char ***'
hvar = &evar; // 'char const ***' -> 'char ***'
hvar = &econst; // 'char const **const *' -> 'char ***'
hvar = &fvar; // 'char *const **' -> 'char ***'
hvar = &fconst; // 'char const **const *' -> 'char ***'
hvar = &gvar; // 'char const *const **' -> 'char ***'
hvar = &gconst; // 'char const *const *const *' -> 'char ***'

ivar = &dvar; // 'char ***' -> 'char const ***'
ivar = &dconst; // 'char **const *' -> 'char const ***'
ivar = &evar; // OK:'char const ***' -> 'char const ***'
ivar = &econst; // 'char const **const *' -> 'char const ***'
ivar = &fvar; // 'char *const **' -> 'char const ***'
ivar = &fconst; // 'char const **const *' -> 'char const ***'
ivar = &gvar; // 'char const *const **' -> 'char const ***'
ivar = &gconst; // 'char const *const *const *' -> 'char const ***'

jvar = &dvar; // 'char ***' -> 'char *const **'
jvar = &dconst; // 'char **const *' -> 'char *const **'
jvar = &evar; // 'char const ***' -> 'char *const **'
jvar = &econst; // 'char const **const *' -> 'char *const **'
jvar = &fvar; // OK'char *const **' -> 'char *const **'
jvar = &fconst; // 'char const **const *' -> 'char *const **'
jvar = &gvar; // 'char const *const **' -> 'char *const **'
jvar = &gconst; // 'char const *const *const *' -> 'char *const **'

kvar = &dvar; // 'char ***' -> 'char const * const **'
kvar = &dconst; // 'char **const *' -> 'char const * const **'
kvar = &evar; // 'char const ***' -> 'char const * const **'
kvar = &econst; // 'char const **const *' -> 'char const * const
**'
kvar = &fvar; // 'char *const **' -> 'char const * const **'
kvar = &fconst; // 'char const **const *' -> 'char const * const
**'
kvar = &gvar; // OK: 'char const *const **' -> 'char const * const
**'
kvar = &gconst; // 'char const *const *const *' -> 'char const *
const **'
}


------



particular instance, and if realization's never changed, C90 or K&R
would still suffice today.
Fine. Find me the relevant text that allows the assignment in C90.
You obviously won't find it in K&R because it didn't have 'const' at
all.declaration that the variable or parameter will not be modified from
this variable.
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top