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


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

on the order of the const-keyword

Started byMeredith Montgomery <mmontgomery@levado.to>
First post2021-10-28 12:50 -0300
Last post2021-10-29 17:04 -0300
Articles 20 on this page of 32 — 10 participants

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


Contents

  on the order of the const-keyword Meredith Montgomery <mmontgomery@levado.to> - 2021-10-28 12:50 -0300
    Re: on the order of the const-keyword Bart <bc@freeuk.com> - 2021-10-28 17:25 +0100
      Re: on the order of the const-keyword "james...@alumni.caltech.edu" <jameskuyper@alumni.caltech.edu> - 2021-10-28 10:10 -0700
        Re: on the order of the const-keyword Guillaume <message@bottle.org> - 2021-10-28 20:40 +0200
        Re: on the order of the const-keyword Meredith Montgomery <mmontgomery@levado.to> - 2021-10-29 00:07 -0300
          Re: on the order of the const-keyword James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-10-29 00:48 -0400
      Re: on the order of the const-keyword Thiago Adams <thiago.adams@gmail.com> - 2021-10-28 12:56 -0700
        Re: on the order of the const-keyword Thiago Adams <thiago.adams@gmail.com> - 2021-10-28 13:18 -0700
          Re: on the order of the const-keyword Bart <bc@freeuk.com> - 2021-10-28 21:35 +0100
            Re: on the order of the const-keyword Thiago Adams <thiago.adams@gmail.com> - 2021-10-28 13:57 -0700
              Re: on the order of the const-keyword Thiago Adams <thiago.adams@gmail.com> - 2021-10-28 14:07 -0700
                Re: on the order of the const-keyword Bart <bc@freeuk.com> - 2021-10-28 22:54 +0100
                Re: on the order of the const-keyword Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-10-28 15:37 -0700
                  Re: on the order of the const-keyword Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-10-29 00:02 +0100
          Re: on the order of the const-keyword Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-10-28 22:10 +0100
          Re: on the order of the const-keyword Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-10-28 15:13 -0700
          Re: on the order of the const-keyword Meredith Montgomery <mmontgomery@levado.to> - 2021-10-29 00:40 -0300
      Re: on the order of the const-keyword Meredith Montgomery <mmontgomery@levado.to> - 2021-10-28 23:48 -0300
    Re: on the order of the const-keyword James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-10-28 13:04 -0400
      Re: on the order of the const-keyword Meredith Montgomery <mmontgomery@levado.to> - 2021-10-29 00:34 -0300
    Re: on the order of the const-keyword David Brown <david.brown@hesbynett.no> - 2021-10-29 10:03 +0200
      Re: on the order of the const-keyword Bart <bc@freeuk.com> - 2021-10-29 11:30 +0100
        Re: on the order of the const-keyword David Brown <david.brown@hesbynett.no> - 2021-10-29 16:31 +0200
          Re: on the order of the const-keyword Bart <bc@freeuk.com> - 2021-10-29 16:45 +0100
            Re: on the order of the const-keyword David Brown <david.brown@hesbynett.no> - 2021-10-29 18:30 +0200
              Re: on the order of the const-keyword Manfred <noname@add.invalid> - 2021-10-30 00:32 +0200
                Re: on the order of the const-keyword Meredith Montgomery <mmontgomery@levado.to> - 2021-10-29 20:03 -0300
                Re: on the order of the const-keyword Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-10-30 01:10 +0100
              Re: on the order of the const-keyword Bart <bc@freeuk.com> - 2021-10-29 23:51 +0100
      Re: on the order of the const-keyword Meredith Montgomery <mmontgomery@levado.to> - 2021-10-29 12:22 -0300
        Re: on the order of the const-keyword David Brown <david.brown@hesbynett.no> - 2021-10-29 18:34 +0200
          Re: on the order of the const-keyword Meredith Montgomery <mmontgomery@levado.to> - 2021-10-29 17:04 -0300

Page 1 of 2  [1] 2  Next page →


#163193 — on the order of the const-keyword

FromMeredith Montgomery <mmontgomery@levado.to>
Date2021-10-28 12:50 -0300
Subjecton the order of the const-keyword
Message-ID<86mtmtm9m1.fsf@levado.to>
These seem legal declarations in C:

  const char msg[9] = "warming:";
  char const msg[9] = "warming:";

What's the difference between them?

(*) Note to self

When I tried changing that array, the compiler did not let me to ---
with either declaration.  (So it appears there is no *effective*
difference.)

%cat msg.c
#include <stdio.h>

int main(void) {

  char const msg[9] = "warming:";
  msg[0]= 'f';
  printf("%s\n", msg);
  
}
%make msg
gcc     msg.c   -o msg
msg.c: In function 'main':
msg.c:6:9: error: assignment of read-only location 'msg[0]'
    6 |   msg[0]= 'f';
      |         ^
make: *** [<builtin>: msg] Error 1
%

[toc] | [next] | [standalone]


#163196

FromBart <bc@freeuk.com>
Date2021-10-28 17:25 +0100
Message-ID<sleiul$8m0$1@dont-email.me>
In reply to#163193
On 28/10/2021 16:50, Meredith Montgomery wrote:
> These seem legal declarations in C:
> 
>    const char msg[9] = "warming:";
>    char const msg[9] = "warming:";
> 
> What's the difference between them?


There is no difference. You can even write:

  const char const msg[9];


'const' (as well as short, int, long, float, double, even static and 
typedef) can occur anywhere, in any combination, in the declaration of a 
base type (what goes on the left before the first variable).

'const' can also be repeated any number of times:

    char const const const const const const msg[9]

if you want to be certain that msg is constant!

However when applied to a pointer, then it must go after *.

[toc] | [prev] | [next] | [standalone]


#163198

From"james...@alumni.caltech.edu" <jameskuyper@alumni.caltech.edu>
Date2021-10-28 10:10 -0700
Message-ID<2a5589c2-89ac-4d77-a91d-508c00f75e43n@googlegroups.com>
In reply to#163196
On Thursday, October 28, 2021 at 12:26:09 PM UTC-4, Bart wrote:
...
> 'const' (as well as short, int, long, float, double, even static and 
> typedef) can occur anywhere, in any combination, in the declaration of a 
> base type (what goes on the left before the first variable). 
...
> However when applied to a pointer, then it must go after *.

const char * p
char * const q;
char const * const r;

are all permitted. p is a pointer to const char. q is a const pointer to char. r is a const pointer to const char.

[toc] | [prev] | [next] | [standalone]


#163199

FromGuillaume <message@bottle.org>
Date2021-10-28 20:40 +0200
Message-ID<sleqrn$d2j$1@gioia.aioe.org>
In reply to#163198
Le 28/10/2021 à 19:10, james...@alumni.caltech.edu a écrit :
> On Thursday, October 28, 2021 at 12:26:09 PM UTC-4, Bart wrote:
> ...
>> 'const' (as well as short, int, long, float, double, even static and
>> typedef) can occur anywhere, in any combination, in the declaration of a
>> base type (what goes on the left before the first variable).
> ...
>> However when applied to a pointer, then it must go after *.
> 
> const char * p
> char * const q;
> char const * const r;
> 
> are all permitted. p is a pointer to const char. q is a const pointer to char. r is a const pointer to const char.

Yes indeed!
With pointer declarations, 'const' has a different meaning depending on 
where it is located relative to '*', as you showed.

[toc] | [prev] | [next] | [standalone]


#163218

FromMeredith Montgomery <mmontgomery@levado.to>
Date2021-10-29 00:07 -0300
Message-ID<86y26cle9j.fsf@levado.to>
In reply to#163198
"james...@alumni.caltech.edu" <jameskuyper@alumni.caltech.edu> writes:

> On Thursday, October 28, 2021 at 12:26:09 PM UTC-4, Bart wrote:
> ...
>> 'const' (as well as short, int, long, float, double, even static and 
>> typedef) can occur anywhere, in any combination, in the declaration of a 
>> base type (what goes on the left before the first variable). 
> ...
>> However when applied to a pointer, then it must go after *.
>
> const char * p
> char * const q;
> char const * const r;
>
> are all permitted. p is a pointer to const char. q is a const pointer
> to char. r is a const pointer to const char.

So the order does make a difference here.  I mean

 char const * r1

is not the same 

  char const * const r2

because r2 cannot point somewhere else but r1 can.  

Thank you.

(*) So, I wrote this to check

#include <stdio.h>

int main()
{
  const char c1 = 'x';
  const char c2 = 'y';
  
  const char* r1 = &c1;
  const char* const r2 = &c1;
  
  printf("r1 = %c, r2 = %c\n", *r1, *r2);
  
  r1 = &c2;
  /* r2 = &c2; */ /* cant do this */
  printf("r1 = %c, r2 = %c\n", *r1, *r2);
  
  return 0;
}

(*) What have I learned here as well?

When we declare something to be const we also have to define it in the
statement.  IOW, I cannot separate declaration and definition of a const
thing.  This makes sense --- if I can assign a const-thing, how would
the compiler keep me from changing it?  (But it wasn't clear to me 'til
now.)

[toc] | [prev] | [next] | [standalone]


#163225

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2021-10-29 00:48 -0400
Message-ID<slfuf4$p46$1@dont-email.me>
In reply to#163218
On 10/28/21 11:07 PM, Meredith Montgomery wrote:
> "james...@alumni.caltech.edu" <jameskuyper@alumni.caltech.edu> writes:
> 
>> On Thursday, October 28, 2021 at 12:26:09 PM UTC-4, Bart wrote:
>> ...
>>> 'const' (as well as short, int, long, float, double, even static and 
>>> typedef) can occur anywhere, in any combination, in the declaration of a 
>>> base type (what goes on the left before the first variable). 
>> ...
>>> However when applied to a pointer, then it must go after *.
>>
>> const char * p
>> char * const q;
>> char const * const r;
>>
>> are all permitted. p is a pointer to const char. q is a const pointer
>> to char. r is a const pointer to const char.
> 
> So the order does make a difference here.  I mean
> 
>  char const * r1
> 
> is not the same 
> 
>   char const * const r2
> 
> because r2 cannot point somewhere else but r1 can.  
> 
> Thank you.

The top-level grammar for such a declaration is

declaration-specifiers init-declarator-list opt ;

"char const" are the declaration specifiers, while the
init-declarator-list consists of a single declarator with no
initializer, which is "* const r2". "r2" is the identifier being
declared, and after any "*" in a declarator there may be additional type
qualifiers that are not part of the initial list of declaration
specifiers. Unlike the order of the declaration specifiers, the order of
the type qualifiers relative to the "*"s is VERY important.

[toc] | [prev] | [next] | [standalone]


#163201

FromThiago Adams <thiago.adams@gmail.com>
Date2021-10-28 12:56 -0700
Message-ID<a25df1f0-687b-4489-8f2f-6daa35593040n@googlegroups.com>
In reply to#163196
On Thursday, October 28, 2021 at 1:26:09 PM UTC-3, Bart wrote:
> On 28/10/2021 16:50, Meredith Montgomery wrote: 
> > These seem legal declarations in C: 
> > 
> > const char msg[9] = "warming:"; 
> > char const msg[9] = "warming:"; 
> > 
> > What's the difference between them?
> There is no difference. You can even write: 
> 
> const char const msg[9]; 
> 
> 
> 'const' (as well as short, int, long, float, double, even static and 
> typedef) can occur anywhere, in any combination, in the declaration of a 
> base type (what goes on the left before the first variable). 
> 
> 'const' can also be repeated any number of times: 
> 
> char const const const const const const msg[9] 

We can also add as many parentheses as we like.
char const const const const const const ((((((msg))))))[9];
:D


[toc] | [prev] | [next] | [standalone]


#163202

FromThiago Adams <thiago.adams@gmail.com>
Date2021-10-28 13:18 -0700
Message-ID<994066a9-5940-4d1c-8df4-517905174930n@googlegroups.com>
In reply to#163201
On Thursday, October 28, 2021 at 4:56:18 PM UTC-3, Thiago Adams wrote:
...
> > 'const' (as well as short, int, long, float, double, even static and 
> > typedef) can occur anywhere, in any combination, in the declaration of a 
> > base type (what goes on the left before the first variable). 

I also have a new definition for typedef considering how it works.

We use to say typedef is a alias for a type name.

But here , 

typedef int Int;
typedef unsigned Int T; //error

Int does not work as a alias for int.

So my definition  is:
when we put typedef in a declaration we declare a variable that has no 
storage. 

When we use this variable is the same of using typeof(variable) but
we write just the variable name.
Int x;
So typedef is more like "use the same type of that variable here".

considering this.... I was also considering to use typedef to define constants

typedef double pi = 3.14;
or 
valuedef double pi = 3.14; 

pi is a non-storage variable, but instead of copying its type
we copy its initialization value.

double x = pi;






[toc] | [prev] | [next] | [standalone]


#163203

FromBart <bc@freeuk.com>
Date2021-10-28 21:35 +0100
Message-ID<slf1ic$qcv$1@dont-email.me>
In reply to#163202
On 28/10/2021 21:18, Thiago Adams wrote:
> On Thursday, October 28, 2021 at 4:56:18 PM UTC-3, Thiago Adams wrote:
> ...
>>> 'const' (as well as short, int, long, float, double, even static and
>>> typedef) can occur anywhere, in any combination, in the declaration of a
>>> base type (what goes on the left before the first variable).
> 
> I also have a new definition for typedef considering how it works.
> 
> We use to say typedef is a alias for a type name.
> 
> But here ,
> 
> typedef int Int;
> typedef unsigned Int T; //error
> 
> Int does not work as a alias for int.

I think this is reasonable behavour. To make it work as you want, as an 
alias for the 'int' /token/, then it can be done as:

   #define Int int

For a composite type like 'int long long', it must be a valid 
combination of those tokens. The alias 'T' may be defined internally as 
a complete type 'signed long long int'.

You can't then modify it as 'unsigned signed long long int' even if you 
could sort out the parsing.

For example, you can't do 'unsigned int32_t'.

> 
> So my definition  is:
> when we put typedef in a declaration we declare a variable that has no
> storage.

I can never remember how typedef works, and have to pretend that it is 
'static', and I'm declaring a normal variable name.


> When we use this variable is the same of using typeof(variable) but
> we write just the variable name.
> Int x;
> So typedef is more like "use the same type of that variable here".
> 
> considering this.... I was also considering to use typedef to define constants
> 
> typedef double pi = 3.14;
> or
> valuedef double pi = 3.14;
> 
> pi is a non-storage variable, but instead of copying its type
> we copy its initialization value.

I tried something like that. I couldn't use 'const' as that was taken; I 
used 'constant':

	constant int a = 1233;
	constant double b = a/10.0;

	printf("%d\n", a);
	printf("%f\n", b);

This could be tweaked to infer the type from the expression.

[toc] | [prev] | [next] | [standalone]


#163204

FromThiago Adams <thiago.adams@gmail.com>
Date2021-10-28 13:57 -0700
Message-ID<7697a67c-fc7e-4b7c-b53f-38076b50cde2n@googlegroups.com>
In reply to#163203
On Thursday, October 28, 2021 at 5:35:36 PM UTC-3, Bart wrote:
> On 28/10/2021 21:18, Thiago Adams wrote: 
> > On Thursday, October 28, 2021 at 4:56:18 PM UTC-3, Thiago Adams wrote: 
> > ... 
> >>> 'const' (as well as short, int, long, float, double, even static and 
> >>> typedef) can occur anywhere, in any combination, in the declaration of a 
> >>> base type (what goes on the left before the first variable). 
> > 
> > I also have a new definition for typedef considering how it works. 
> > 
> > We use to say typedef is a alias for a type name. 
> > 
> > But here , 
> > 
> > typedef int Int; 
> > typedef unsigned Int T; //error 
> > 
> > Int does not work as a alias for int.
> I think this is reasonable behavour. To make it work as you want, as an 
> alias for the 'int' /token/, then it can be done as: 
> 
> #define Int int 
> 
> For a composite type like 'int long long', it must be a valid 
> combination of those tokens. The alias 'T' may be defined internally as 
> a complete type 'signed long long int'. 
> 
> You can't then modify it as 'unsigned signed long long int' even if you 
> could sort out the parsing. 
> 
> For example, you can't do 'unsigned int32_t'.
> > 
> > So my definition is: 
> > when we put typedef in a declaration we declare a variable that has no 
> > storage.
> I can never remember how typedef works, and have to pretend that it is 
> 'static', and I'm declaring a normal variable name.
> > When we use this variable is the same of using typeof(variable) but 
> > we write just the variable name. 
> > Int x; 
> > So typedef is more like "use the same type of that variable here". 
> > 
> > considering this.... I was also considering to use typedef to define constants 
> > 
> > typedef double pi = 3.14; 
> > or 
> > valuedef double pi = 3.14; 
> > 
> > pi is a non-storage variable, but instead of copying its type 
> > we copy its initialization value.
> I tried something like that. I couldn't use 'const' as that was taken; I 
> used 'constant': 
> 
> constant int a = 1233; 
> constant double b = a/10.0; 
> 
> printf("%d\n", a); 
> printf("%f\n", b); 
> 
> This could be tweaked to infer the type from the expression.

and because there is no storage  we cannot take &a or &b. 
BUT I think  there is a hidden variable instantiated (just like compound literals)

For instance this is C99.

struct X {   int i; };
void F(struct X* x) {}
struct X c = { . i = 1 };
int main() {
  F(& (struct X) {.i = 1}); //variable is created
  F(&c);
}

in this C99 sample c HAS storage. it exists.
Now lets consider we have this "constant".

struct X {   int i; };
void F(struct X* x) {}
constant struct X c = { . i = 1 }; //no storage

int main() {
  F(& (struct X) {.i = 1}); 
  F(&c); //what happens here?
}

When we call F(&c)  some variable should be instantiated.?

At the end it could work as enumerators work today 

enum { A = 1 };
void F(int* i) {}
void F2(int i) {}
int main() {
  F(&A); //error: lvalue required as unary '&' operand
  F2(A); //OK
}

sometimes  a local variable would be created, except for int double etc..

[toc] | [prev] | [next] | [standalone]


#163205

FromThiago Adams <thiago.adams@gmail.com>
Date2021-10-28 14:07 -0700
Message-ID<aadf2b60-6c41-434a-8c19-8fc2a60bff15n@googlegroups.com>
In reply to#163204
On Thursday, October 28, 2021 at 5:57:38 PM UTC-3, Thiago Adams wrote:
> On Thursday, October 28, 2021 at 5:35:36 PM UTC-3, Bart wrote: 
> > On 28/10/2021 21:18, Thiago Adams wrote: 
> > > On Thursday, October 28, 2021 at 4:56:18 PM UTC-3, Thiago Adams wrote: 
> > > ... 
> > >>> 'const' (as well as short, int, long, float, double, even static and 
> > >>> typedef) can occur anywhere, in any combination, in the declaration of a 
> > >>> base type (what goes on the left before the first variable). 
> > > 
> > > I also have a new definition for typedef considering how it works. 
> > > 
> > > We use to say typedef is a alias for a type name. 
> > > 
> > > But here , 
> > > 
> > > typedef int Int; 
> > > typedef unsigned Int T; //error 
> > > 
> > > Int does not work as a alias for int. 
> > I think this is reasonable behavour. To make it work as you want, as an 
> > alias for the 'int' /token/, then it can be done as: 
> > 
> > #define Int int 
> > 
> > For a composite type like 'int long long', it must be a valid 
> > combination of those tokens. The alias 'T' may be defined internally as 
> > a complete type 'signed long long int'. 
> > 
> > You can't then modify it as 'unsigned signed long long int' even if you 
> > could sort out the parsing. 
> > 
> > For example, you can't do 'unsigned int32_t'. 
> > > 
> > > So my definition is: 
> > > when we put typedef in a declaration we declare a variable that has no 
> > > storage. 
> > I can never remember how typedef works, and have to pretend that it is 
> > 'static', and I'm declaring a normal variable name. 
> > > When we use this variable is the same of using typeof(variable) but 
> > > we write just the variable name. 
> > > Int x; 
> > > So typedef is more like "use the same type of that variable here". 
> > > 
> > > considering this.... I was also considering to use typedef to define constants 
> > > 
> > > typedef double pi = 3.14; 
> > > or 
> > > valuedef double pi = 3.14; 
> > > 
> > > pi is a non-storage variable, but instead of copying its type 
> > > we copy its initialization value. 
> > I tried something like that. I couldn't use 'const' as that was taken; I 
> > used 'constant': 
> > 
> > constant int a = 1233; 
> > constant double b = a/10.0; 
> > 
> > printf("%d\n", a); 
> > printf("%f\n", b); 
> > 
> > This could be tweaked to infer the type from the expression.
> and because there is no storage we cannot take &a or &b. 
> BUT I think there is a hidden variable instantiated (just like compound literals) 
> 
> For instance this is C99. 
> 
> struct X { int i; }; 
> void F(struct X* x) {} 
> struct X c = { . i = 1 }; 
> int main() { 
> F(& (struct X) {.i = 1}); //variable is created 
> F(&c); 
> } 
> 
> in this C99 sample c HAS storage. it exists. 
> Now lets consider we have this "constant". 
> 
> struct X { int i; }; 
> void F(struct X* x) {} 
> constant struct X c = { . i = 1 }; //no storage 
> 
> int main() { 
> F(& (struct X) {.i = 1}); 
> F(&c); //what happens here? 
> } 
> 
> When we call F(&c) some variable should be instantiated.? 
> 
> At the end it could work as enumerators work today 
> 
> enum { A = 1 }; 
> void F(int* i) {} 
> void F2(int i) {} 
> int main() { 
> F(&A); //error: lvalue required as unary '&' operand 
> F2(A); //OK 
> } 
> 
> sometimes a local variable would be created, except for int double etc..

The reason why this features does not exist today may be because for complex 
types we can create a const variable and reuse it. 
and use defines for int double etc.



[toc] | [prev] | [next] | [standalone]


#163208

FromBart <bc@freeuk.com>
Date2021-10-28 22:54 +0100
Message-ID<slf67a$pu0$1@dont-email.me>
In reply to#163205
On 28/10/2021 22:07, Thiago Adams wrote:
> On Thursday, October 28, 2021 at 5:57:38 PM UTC-3, Thiago Adams wrote:

>> in this C99 sample c HAS storage. it exists.
>> Now lets consider we have this "constant".
>>
>> struct X { int i; };
>> void F(struct X* x) {}
>> constant struct X c = { . i = 1 }; //no storage
>>
>> int main() {
>> F(& (struct X) {.i = 1});
>> F(&c); //what happens here?
>> }
>>
>> When we call F(&c) some variable should be instantiated.?
>>
>> At the end it could work as enumerators work today
>>
>> enum { A = 1 };
>> void F(int* i) {}
>> void F2(int i) {}
>> int main() {
>> F(&A); //error: lvalue required as unary '&' operand
>> F2(A); //OK
>> }
>>
>> sometimes a local variable would be created, except for int double etc..
> 
> The reason why this features does not exist today may be because for complex
> types we can create a const variable and reuse it.
> and use defines for int double etc.

Below is a summary, in the first 3 Y/N columns, of the three different 
ways C has to create named constants.

It's set up so that a Y response is the more desirable.

Here, enums tick nearly all the boxes, so that it is odd that #define 
and const T seem more popular. But then, 'enum' was really intended for 
other purposes (defining related names with incrementing values), so it 
might itself seem odd to use it arbitrarily.

My 'constant' feature ticks all the boxes plus it doesn't look weird to use.


   Characteristic              #define  const T  enum  'constant'

   Normal scope?                N        Y        Y      Y
   Any numeric type?            Y        Y        N      Y
   Avoids storage (5)           Y        N (3)    Y      Y
   Use in non-VLA  bounds       Y        N        Y      Y
   Won't create a VLA?          Y        N        Y      Y
   Use in static array bounds   Y        N        Y      Y
   Use in switch-case labels    Y        N        Y      Y
   Evaluate once (1)            N        Y        Y      Y
   Prohibit & address-of        Y        N        Y      Y
   Prohibit Pass by ref         Y        N        Y      Y
   Impossible to modify?        Y        N (2)    Y      Y
   Reduce const exprs?          Y        ? (3)    Y      Y
   Unambiguous meaning (4)      N        Y        Y      Y

   (1) With #define A ((B+C)*D) etc, at each place A is used, it will 
expand that expression, and need to parse it and reduce, possibly 100s 
of times

   (2) It's possible to modify via casts

   (3) Depends on compiler's optimisation abilities

   (4) With #define, using the same ((B+C)*D) example each time A is 
expanded, it will use whatever B, C, D names are in scope at that point, 
potentially generating a different value of A each time.

   (5) Apart from immediate operands, some hardware may require storage 
for certain float operands for example. But this is not accessible to C 
programs.

[toc] | [prev] | [next] | [standalone]


#163210

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2021-10-28 15:37 -0700
Message-ID<875ytg22ty.fsf@nosuchdomain.example.com>
In reply to#163205
Thiago Adams <thiago.adams@gmail.com> writes:
> On Thursday, October 28, 2021 at 5:57:38 PM UTC-3, Thiago Adams wrote:
[...]
>> At the end it could work as enumerators work today 
>> 
>> enum { A = 1 }; 
>> void F(int* i) {} 
>> void F2(int i) {} 
>> int main() { 
>> F(&A); //error: lvalue required as unary '&' operand 
>> F2(A); //OK 
>> } 
>> 
>> sometimes a local variable would be created, except for int double etc..
>
> The reason why this features does not exist today may be because for complex 
> types we can create a const variable and reuse it. 
> and use defines for int double etc.

C's "const" keyword does not mean "constant", and it never has.  Of
course the spelling is derived from the English word "constant", which
can cause some understandable confusion.

A *constant expression* is one that can be evaluated at compile time.
A *constant* is a literal.

The keyword "const" might more accurately have been spelled "readonly".
If a name is const-qualified, it means that the named object cannot be
modified via that name.  Defining something as "const" never makes
its name a constant expression.

C++ added a special case, so that for example
    const int n = 42;
makes the expression n a constant expression (though n is still an
object whose address can be taken).  Later, C++ added the "constexpr"
keyword (like "const" but it requires the initializer to be constant),
which in my opinion would have been a better choice for this special
case.

Note that this:
    const time_t now = time(NULL);
is perfectly legal; the expression t cannot even in principle be
evaluated at compile time.  (`constexpr time_t now = time(NULL);`
is invalid in C++.)

I wouldn't mind seeing a future version of C adopt something like C++'s
"constexpr" -- *without* changing the current meaning of "const".

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#163211

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2021-10-29 00:02 +0100
Message-ID<87lf2cvjm2.fsf@bsb.me.uk>
In reply to#163210
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

> I wouldn't mind seeing a future version of C adopt something like C++'s
> "constexpr" -- *without* changing the current meaning of "const".

It's been proposed:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2851.pdf

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#163206

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2021-10-28 22:10 +0100
Message-ID<87r1c4voru.fsf@bsb.me.uk>
In reply to#163202
Thiago Adams <thiago.adams@gmail.com> writes:

> On Thursday, October 28, 2021 at 4:56:18 PM UTC-3, Thiago Adams wrote:
> ...
>> > 'const' (as well as short, int, long, float, double, even static and 
>> > typedef) can occur anywhere, in any combination, in the declaration of a 
>> > base type (what goes on the left before the first variable). 
>
> I also have a new definition for typedef considering how it works.
>
> We use to say typedef is a alias for a type name.

"We"?  The standard doesn't.  It says the declaration defines a "typedef
name".  I agree it's handy to think of it as an alias, but you have to
take care with analogies in technical situations.

> But here , 
>
> typedef int Int;
> typedef unsigned Int T; //error
>
> Int does not work as a alias for int.

An alias does not work in all contexts.  I may be know as Shorty down
the club, but I can't put that on my passport.  Sometimes the "proper"
name is needed.

> So my definition  is:
> when we put typedef in a declaration we declare a variable that has no 
> storage.

Well typedef is, syntactically, a storage class specifier like extern,
static and register, so I can see why you might prefer that analogy.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#163209

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2021-10-28 15:13 -0700
Message-ID<87a6is23xa.fsf@nosuchdomain.example.com>
In reply to#163202
Thiago Adams <thiago.adams@gmail.com> writes:
> On Thursday, October 28, 2021 at 4:56:18 PM UTC-3, Thiago Adams wrote:
> ...
>> > 'const' (as well as short, int, long, float, double, even static and 
>> > typedef) can occur anywhere, in any combination, in the declaration of a 
>> > base type (what goes on the left before the first variable). 
>
> I also have a new definition for typedef considering how it works.
>
> We use to say typedef is a alias for a type name.
>
> But here , 
>
> typedef int Int;
> typedef unsigned Int T; //error
>
> Int does not work as a alias for int.

Yes, it absolutely does.  Given your first declaration, `Int` is an
alias for the *type* `int`, not for the *keyword* `int`.  It's not a
macro, and it doesn't act like one.

The `unsigned` keyword can only be used as the syntax allows, and the
syntax doesn't allow it to be used with a typedef name.  The `unsigned`
keyword can be used by itself as a type name, or along with the `char`,
`short`, `int`, and/or `long` keywords, as defined in N1570 6.7.2.

> So my definition  is:
> when we put typedef in a declaration we declare a variable that has no 
> storage. 

No, that's not what it does.  It doesn't declare a variable at all, with
or without storage, unless you stretch the meaning of "variable" almost
beyond recognition.  (Note that the C standard doesn't use the term
"variable".).  Rather, the `typedef` keyword is treated as a storage
class specifier for syntactic convenience.

> When we use this variable is the same of using typeof(variable) but
> we write just the variable name.
> Int x;
> So typedef is more like "use the same type of that variable here".
>
> considering this.... I was also considering to use typedef to define constants
>
> typedef double pi = 3.14;
> or 
> valuedef double pi = 3.14; 
>
> pi is a non-storage variable, but instead of copying its type
> we copy its initialization value.
>
> double x = pi;

That's more or less what `constexpr` does in C++, and what `const`
*almost* does in C.  Using `typedef` for this would not in my opinion
make sense.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#163220

FromMeredith Montgomery <mmontgomery@levado.to>
Date2021-10-29 00:40 -0300
Message-ID<86ilxglcqj.fsf@levado.to>
In reply to#163202
Thiago Adams <thiago.adams@gmail.com> writes:

[...]

> So my definition is: when we put typedef in a declaration we declare a
> variable that has no storage.

I don't like to say a variable that has no storage.  Even the literal
constants written in the body of your programs are loaded in memory and
the place they occupy *is* storage.

Of course, the whole idea that numbers represent themselves (and the
fact that in languages like C we cannot get the address of literal
number) encourages us to think like you do above, but I think that's not
a very good idea.

[toc] | [prev] | [next] | [standalone]


#163217

FromMeredith Montgomery <mmontgomery@levado.to>
Date2021-10-28 23:48 -0300
Message-ID<86h7d0mtqp.fsf@levado.to>
In reply to#163196
Bart <bc@freeuk.com> writes:

> On 28/10/2021 16:50, Meredith Montgomery wrote:
>> These seem legal declarations in C:
>>    const char msg[9] = "warming:";
>>    char const msg[9] = "warming:";
>> What's the difference between them?
>
> There is no difference. You can even write:
>
>  const char const msg[9];
>
>
> 'const' (as well as short, int, long, float, double, even static and
> typedef) can occur anywhere, in any combination, in the declaration of
> a base type (what goes on the left before the first variable).
>
> 'const' can also be repeated any number of times:
>
>    char const const const const const const msg[9]
>
> if you want to be certain that msg is constant!
>
> However when applied to a pointer, then it must go after *.

Very interesting.  Thank you so much for this.

[toc] | [prev] | [next] | [standalone]


#163197

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2021-10-28 13:04 -0400
Message-ID<slel67$ppc$1@dont-email.me>
In reply to#163193
On 10/28/21 11:50 AM, Meredith Montgomery wrote:
> These seem legal declarations in C:
> 
>   const char msg[9] = "warming:";
>   char const msg[9] = "warming:";
> 
> What's the difference between them?
> 
> (*) Note to self
> 
> When I tried changing that array, the compiler did not let me to ---
> with either declaration.  (So it appears there is no *effective*
> difference.)
> 
> %cat msg.c
> #include <stdio.h>
> 
> int main(void) {
> 
>   char const msg[9] = "warming:";
>   msg[0]= 'f';
>   printf("%s\n", msg);
>   
> }
> %make msg
> gcc     msg.c   -o msg
> msg.c: In function 'main':
> msg.c:6:9: error: assignment of read-only location 'msg[0]'
>     6 |   msg[0]= 'f';
>       |         ^
> make: *** [<builtin>: msg] Error 1
> %
> 

"const" is a type qualifier. "char" is a type specifier. Both are
members of the larger category called "declaration specifiers". If you
have a string of declaration specifiers, they can occur in any order you
like, without any change of meaning.

[toc] | [prev] | [next] | [standalone]


#163219

FromMeredith Montgomery <mmontgomery@levado.to>
Date2021-10-29 00:34 -0300
Message-ID<86sfwkld1p.fsf@levado.to>
In reply to#163197
James Kuyper <jameskuyper@alumni.caltech.edu> writes:

> On 10/28/21 11:50 AM, Meredith Montgomery wrote:
>> These seem legal declarations in C:
>> 
>>   const char msg[9] = "warming:";
>>   char const msg[9] = "warming:";
>> 
>> What's the difference between them?
>> 
>> (*) Note to self
>> 
>> When I tried changing that array, the compiler did not let me to ---
>> with either declaration.  (So it appears there is no *effective*
>> difference.)
>> 
>> %cat msg.c
>> #include <stdio.h>
>> 
>> int main(void) {
>> 
>>   char const msg[9] = "warming:";
>>   msg[0]= 'f';
>>   printf("%s\n", msg);
>>   
>> }
>> %make msg
>> gcc     msg.c   -o msg
>> msg.c: In function 'main':
>> msg.c:6:9: error: assignment of read-only location 'msg[0]'
>>     6 |   msg[0]= 'f';
>>       |         ^
>> make: *** [<builtin>: msg] Error 1
>> %
>> 
>
> "const" is a type qualifier. "char" is a type specifier. Both are
> members of the larger category called "declaration specifiers". If you
> have a string of declaration specifiers, they can occur in any order you
> like, without any change of meaning.

That's a nice description.  Thank you.  I'm making the following
parallel in my mind:

  type qualifier /is like/ an adjective
  type specifier /is like/ a noun

(``Let c be /char/ming, but qualify it as unmovable.'')

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c


csiph-web