Discussion:
constexpr keyword is unnecessary
(too old to reply)
Thiago Adams
2024-10-11 12:25:19 UTC
Permalink
I think constexpr keyword is unnecessary.
Anything you do with it could/should be done with const.

Even without const , one object like (struct point){.x=1, .y=0} is a
constant in my view.

So, for instance, no need for (constexpr struct point){.x=1, .y=0} here.

The VLA could have been the motivation for a new keyword, but I don’t
think it matters.

On the other hand, (static struct point){.x=1, .y=0} makes sense.

If constexpr were "no-storage" I think it would make sense but it is not.
Bonita Montero
2024-10-11 18:03:27 UTC
Permalink
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Anything you do with it could/should be done with const.
Even without const , one object like (struct point){.x=1, .y=0} is a
constant in my view.
So, for instance, no need for (constexpr struct point){.x=1, .y=0} here.
The VLA could have been the motivation for a new keyword, but I don’t
think it matters.
On the other hand, (static struct point){.x=1, .y=0} makes sense.
If constexpr were "no-storage" I think it would make sense but it is not.
const doesn't replace constexpr. constexpr is when you want to
assure that the variable is compile-time generated. You can't
enforse this constraint with const.
But I find all these attempts to modernize C hopeless. C wants
to remain a minimalist language and is therefore light years
behind other languages. For me, C is intended to be used when
a more advanced lanugage is not available.
Thiago Adams
2024-10-11 18:11:17 UTC
Permalink
Post by Bonita Montero
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Anything you do with it could/should be done with const.
Even without const , one object like (struct point){.x=1, .y=0} is a
constant in my view.
So, for instance, no need for (constexpr struct point){.x=1, .y=0} here.
The VLA could have been the motivation for a new keyword, but I don’t
think it matters.
On the other hand, (static struct point){.x=1, .y=0} makes sense.
If constexpr were "no-storage" I think it would make sense but it is not.
const doesn't replace constexpr. constexpr is when you want to
assure that the variable is compile-time generated. You can't
enforse this constraint with const.
What I am saying is make const do that. No need for a new keyword.
Post by Bonita Montero
But I find all these attempts to modernize C hopeless. C wants
to remain a minimalist language and is therefore light years
behind other languages. For me, C is intended to be used when
a more advanced lanugage is not available.
constant expression make sense in C. It is not new, it is very old.
The difference now is the extension and this will not make the language
more complicated but more coherent.
Bonita Montero
2024-10-11 19:17:33 UTC
Permalink
Post by Thiago Adams
constant expression make sense in C. It is not new, it is very old.
const has a definition and it allows non compile-time evaluated
variables.
Thiago Adams
2024-10-11 19:30:02 UTC
Permalink
Post by Bonita Montero
Post by Thiago Adams
constant expression make sense in C. It is not new, it is very old.
const has a definition and it allows non compile-time evaluated
variables.
yes. but?

What I am suggesting again is remove the keyword constexpr. make const
do that.

Just to remember C++ was already like that before constexpr. In c++
const could be used as constant expressions.
What C++ could not ensure is that global variables would have a compile
time initialization.
In C all global variables are initialized in compile time.
For local variables like...

const int i = ... ;
the compiler must evaluate the initialization expression if it can be
computed in compile time then i is "constexpr" does not matter if it
have or not the constexpr keyword.
Bonita Montero
2024-10-12 04:39:30 UTC
Permalink
Post by Thiago Adams
Post by Bonita Montero
Post by Thiago Adams
constant expression make sense in C. It is not new, it is very old.
const has a definition and it allows non compile-time evaluated
variables.
yes. but?
With constexpr you could enforce that the expression you assign is
compile-time evaluated. That's while constexpr would make sense.
Post by Thiago Adams
What I am suggesting again is remove the keyword constexpr. make const
do that.
Just to remember C++ was already like that before constexpr. In c++
const could be used as constant expressions.
What C++ could not ensure is that global variables would have a compile
time initialization.
In C all global variables are initialized in compile time.
For local variables like...
const int i = ... ;
the compiler must evaluate the initialization expression if it can be
computed in compile time then i is "constexpr" does not matter if it
have or not the constexpr keyword.
Thiago Adams
2024-10-12 13:23:32 UTC
Permalink
Post by Bonita Montero
Post by Thiago Adams
Post by Bonita Montero
Post by Thiago Adams
constant expression make sense in C. It is not new, it is very old.
const has a definition and it allows non compile-time evaluated
variables.
yes. but?
With constexpr you could enforce that the expression you assign is
compile-time evaluated. That's while constexpr would make sense.
This is already the default in C for file scope variables and places
where constant expression are required like enums.

Let's see local variables, that may or may not have a compile time value.

For instance


int main(){
const int a = 1;
constexpr int i = a; //error
}

i must be initialized with a constant expressions.
What I am suggesting is

const int a = 1; // is a constant expression
const int i = a; // is a constant expression


Note that C++ is already like that
Bonita Montero
2024-10-12 13:52:29 UTC
Permalink
Post by Bonita Montero
With constexpr you could enforce that the expression you assign is
compile-time evaluated. That's while constexpr would make sense.
This is already the default in C for file scope variables ...
They must be optimized away by the compiler and the linker, constexpr
not. And most compile time constants that are constexpr'd in C++ are
local variables. So constexpr makes sense at least for local variables.
Thiago Adams
2024-10-12 21:37:14 UTC
Permalink
Post by Bonita Montero
Post by Bonita Montero
With constexpr you could enforce that the expression you assign is
compile-time evaluated. That's while constexpr would make sense.
This is already the default in C for file scope variables ...
They must be optimized away by the compiler and the linker, constexpr
not. And most compile time constants that are constexpr'd in C++ are
local variables. So constexpr makes sense at least for local variables.
If you are afraid your constant is not constant expression put a
static_assert. Then remove.
And this makes sense only in local scope.

(C++ is a TOTAL mess. const in C++ already could be used n constant
expression)
Bonita Montero
2024-10-13 10:51:09 UTC
Permalink
Post by Thiago Adams
If you are afraid your constant is not constant expression put a
static_assert. Then remove.
This is unnecessary work if you have constexpr.
Post by Thiago Adams
(C++ is a TOTAL mess. const in C++ already could be used n constant
expression)
C++ is five to ten times less work for the same problem.
Thiago Adams
2024-10-13 11:32:18 UTC
Permalink
Post by Bonita Montero
Post by Thiago Adams
If you are afraid your constant is not constant expression put a
static_assert. Then remove.
This is unnecessary work if you have constexpr.
I can say the same of putting constexpr.
And it makes everything more confusing.
Bonita Montero
2024-10-13 11:39:02 UTC
Permalink
Post by Thiago Adams
Post by Bonita Montero
Post by Thiago Adams
If you are afraid your constant is not constant expression put a
static_assert. Then remove.
This is unnecessary work if you have constexpr.
I can say the same of putting constexpr.
And it makes everything more confusing.
Absolutely not, it's easy to read.
With your minimalism mindset you cannot cope with modern demands.
DFS
2024-10-15 03:30:10 UTC
Permalink
Post by Bonita Montero
Post by Thiago Adams
If you are afraid your constant is not constant expression put a
static_assert. Then remove.
This is unnecessary work if you have constexpr.
Post by Thiago Adams
(C++ is a TOTAL mess. const in C++ already could be used n constant
expression)
C++ is five to ten times less work for the same problem.
How do you measure "work'?
Bonita Montero
2024-10-15 11:41:10 UTC
Permalink
Post by DFS
Post by Bonita Montero
Post by Thiago Adams
If you are afraid your constant is not constant expression put a
static_assert. Then remove.
This is unnecessary work if you have constexpr.
Post by Thiago Adams
(C++ is a TOTAL mess. const in C++ already could be used n constant
expression)
C++ is five to ten times less work for the same problem.
How do you measure "work'?
In lines of code. Imagine you would specialize a container like
unordered_map by hand in C. That would be days of work. In C++
it's one line of code and you get nearly optimal performance.
Or just think about what an emplace_back on a vector of strings
all does; if the capacity isn't sufficient a doubled vector is
allocated (libstdc++, libc++), all objects are moved there and
a new item is emplaced at the end. That's one line of code, but
in C that's a half day's work.
Bart
2024-10-15 13:01:46 UTC
Permalink
Post by Bonita Montero
Post by DFS
Post by Bonita Montero
Post by Thiago Adams
If you are afraid your constant is not constant expression put a
static_assert. Then remove.
This is unnecessary work if you have constexpr.
Post by Thiago Adams
(C++ is a TOTAL mess. const in C++ already could be used n constant
expression)
C++ is five to ten times less work for the same problem.
How do you measure "work'?
In lines of code. Imagine you would specialize a container like
unordered_map by hand in C. That would be days of work. In C++
it's one line of code and you get nearly optimal performance.
Or just think about what an emplace_back on a vector of strings
all does; if the capacity isn't sufficient a doubled vector is
allocated (libstdc++, libc++), all objects are moved there and
a new item is emplaced at the end. That's one line of code, but
in C that's a half day's work.
Sure, because every time you start a new C app, you're starting from zero.

There are no existing libraries to use. No online examples to use as
templates. There are no examples of hashtables or growable arrays that
you've implemented over decades of your own work to draw from.

There is NOTHING.

In reality it isn't like that.

Use of C++ does have the advantage when posting bits of code in on-line
forums, since there are a much larger number of /standard/ libraries
that someone running your code will have access to in their
installation, if the code fragment happens to use them.

Posted C code using a non-standard library would be problematical.
That's probably why C code that use a hash-map, for example, may need to
come with its implementation so it may appear to have a higher line count.
Thiago Adams
2024-10-15 13:11:48 UTC
Permalink
Post by Bart
Post by Bonita Montero
Post by DFS
Post by Bonita Montero
Post by Thiago Adams
If you are afraid your constant is not constant expression put a
static_assert. Then remove.
This is unnecessary work if you have constexpr.
Post by Thiago Adams
(C++ is a TOTAL mess. const in C++ already could be used n constant
expression)
C++ is five to ten times less work for the same problem.
How do you measure "work'?
In lines of code. Imagine you would specialize a container like
unordered_map by hand in C. That would be days of work. In C++
it's one line of code and you get nearly optimal performance.
Or just think about what an emplace_back on a vector of strings
all does; if the capacity isn't sufficient a doubled vector is
allocated (libstdc++, libc++), all objects are moved there and
a new item is emplaced at the end. That's one line of code, but
in C that's a half day's work.
Sure, because every time you start a new C app, you're starting from zero.
There are no existing libraries to use. No online examples to use as
templates. There are no examples of hashtables or growable arrays that
you've implemented over decades of your own work to draw from.
There is NOTHING.
In reality it isn't like that.
Use of C++ does have the advantage when posting bits of code in on-line
forums, since there are a much larger number of /standard/ libraries
that someone running your code will have access to in their
installation, if the code fragment happens to use them.
Posted C code using a non-standard library would be problematical.
That's probably why C code that use a hash-map, for example, may need to
come with its implementation so it may appear to have a higher line count.
I think C could be improved a lot with something like ChatGPT to create
parametrized containers.

I was planing to create something (not as advanced of course) but
something I could just write "create a vector of int" "create map of
strings to int" , "create single linked list" etc.
Bonita Montero
2024-10-15 13:27:14 UTC
Permalink
Post by Thiago Adams
I think C could be improved a lot with something like ChatGPT to create
parametrized containers.
Don't usse ChatGPT except for simple code snippets.
With 50 lines or above you get a lot of mistakes.
Janis Papanagnou
2024-10-16 06:35:43 UTC
Permalink
Post by Thiago Adams
Post by Bart
Post by Bonita Montero
Post by Bonita Montero
C++ is five to ten times less work for the same problem.
(I have no numbers, but agree in the general point you make.)
Post by Thiago Adams
Post by Bart
Post by Bonita Montero
In lines of code. Imagine you would specialize a container like
unordered_map by hand in C. That would be days of work. In C++
it's one line of code and you get nearly optimal performance.
Or just think about what an emplace_back on a vector of strings
all does; if the capacity isn't sufficient a doubled vector is
allocated (libstdc++, libc++), all objects are moved there and
a new item is emplaced at the end. That's one line of code, but
in C that's a half day's work.
Sure, because every time you start a new C app, you're starting from zero.
Sadly, considering the practical consequences, yes. (See below.)

(And irony isn't helpful, Bart.)
Post by Thiago Adams
Post by Bart
There are no existing libraries to use. No online examples to use as
templates. There are no examples of hashtables or growable arrays that
you've implemented over decades of your own work to draw from.
There are, a lot! - And since there's no standard everyone's writing
his/her own, or copies *any* hack from "anyone". - It appears to me
like seen with shareware and freeware tools; you can choose between
plenty of contributions, rarely one well designed and none portable.
Some alleviation of the issue is sometimes achieved by use of some
"quasi-standard" libraries that have been established, but that is
neither guaranteed to be existing (in the first place) nor reliable
when used.[*]) And you can also have "fun" if you assemble different
source code packages where each is coming with it's own version of
(non-standard) container functionality.
Post by Thiago Adams
Post by Bart
[...]
Posted C code using a non-standard library would be problematical.
That's probably why C code that use a hash-map, for example, may need
to come with its implementation so it may appear to have a higher line
count.
[...]
I was planing to create something (not as advanced of course) but
something I could just write "create a vector of int" "create map of
strings to int" , "create single linked list" etc.
That's what I meant.

I'd still think it's better to look for an (somewhat) "established"
library that appears to be sophisticatedly written and sufficiently
fulfills your (functional and non-functional) requirements. If we
have the source code available, IME, we often [have to] produce yet
another version branch by changing or adding stuff. Or we want (or
have to) write an adapter or abstraction layer.

Existing code alone, Bart, is not addressing the issue. (Even if you
don't have to write the first chunk of some code.) That's missing the
problems.

(The situation is probably to be valued a bit differently in personal
or isolated projects; this may be where you're coming from?)

Using a well-designed standard library is the way to go. - And less
work, as formulated above, for the same problem _in practice_. YMMV.

Janis

[*] Two decades ago, for example, I used (in a Java project context)
a well designed regexp library from a well-known "contributor". There
were a few to choose from. This one was simple to use (no overhead to
provide unnecessary "flexibility"). Two years later another one, a
complex one, became Java standard. - that example is from practical
experience, and don't think the basic question and inherent problems
and practical implications are different in other language contexts
that don't have a well-designed standard library available for all
the elementary things like data structures.
Kaz Kylheku
2024-10-15 20:31:49 UTC
Permalink
Post by Bart
Sure, because every time you start a new C app, you're starting from zero.
There are no existing libraries to use. No online examples to use as
templates. There are no examples of hashtables or growable arrays that
you've implemented over decades of your own work to draw from.
There is NOTHING.
In reality it isn't like that.
Use of C++ does have the advantage when posting bits of code in on-line
forums, since there are a much larger number of /standard/ libraries
that someone running your code will have access to in their
installation, if the code fragment happens to use them.
C++ standard libraries are such shit that it's standard practice
for any organization to to have its own locally developed libraries.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Bonita Montero
2024-10-16 05:14:35 UTC
Permalink
Post by Kaz Kylheku
C++ standard libraries are such shit that it's standard practice
for any organization to to have its own locally developed libraries.
Can you give a code example and describe why C++ STL is bad with that ?
Janis Papanagnou
2024-10-16 06:44:59 UTC
Permalink
Post by Kaz Kylheku
C++ standard libraries are such shit that it's standard practice
for any organization to to have its own locally developed libraries.
What's your problem with it? (I mean; given that you're just cussing.)

Personally I started coding C++ in professional contexts before STL
was available, let alone in a standardized way; each Unix context had
its own quirks using the first predecessors of the standard STL. It
was really overdue that it got available and standardized.

Concerning the library itself its concepts were outstanding. (Other
libraries in other languages often gave the impression of a loosely
mixed set of ad hoc elements.)

I can see a point that it may be considered difficult to find one's
way into understanding it, especially for folks who don't read the
docs and just try to use them unprepared.

Janis
Kaz Kylheku
2024-10-13 16:39:48 UTC
Permalink
Post by Thiago Adams
What I am suggesting again is remove the keyword constexpr. make const
do that.
Just to remember C++ was already like that before constexpr. In c++
const could be used as constant expressions.
Really?

const int f(int x) { ... }

says that calls to f can be evaluated at compile time?
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Thiago Adams
2024-10-13 17:39:41 UTC
Permalink
Post by Kaz Kylheku
Post by Thiago Adams
What I am suggesting again is remove the keyword constexpr. make const
do that.
Just to remember C++ was already like that before constexpr. In c++
const could be used as constant expressions.
Really?
const int f(int x) { ... }
says that calls to f can be evaluated at compile time?
I am comparing what C have so far. Only variables not functions.

Sample

const int s = 4;
int a[s];

This was always valid in C++.
Bonita Montero
2024-10-13 18:13:07 UTC
Permalink
Post by Thiago Adams
Post by Kaz Kylheku
Post by Thiago Adams
What I am suggesting again is remove the keyword constexpr. make const
do that.
Just to remember C++ was already like that before constexpr. In c++
const could be used as constant expressions.
Really?
   const int f(int x) { ... }
says that calls to f can be evaluated at compile time?
I am comparing what C have so far. Only variables not functions.
Sample
const int s = 4;
int a[s];
This was always valid in C++.
For local variables the constness can be casted away in C++.
Kaz Kylheku
2024-10-13 18:21:46 UTC
Permalink
Post by Thiago Adams
Post by Kaz Kylheku
Post by Thiago Adams
What I am suggesting again is remove the keyword constexpr. make const
do that.
Just to remember C++ was already like that before constexpr. In c++
const could be used as constant expressions.
Really?
const int f(int x) { ... }
says that calls to f can be evaluated at compile time?
I am comparing what C have so far. Only variables not functions.
What C has so far is just lagging behind the C++ constexpr.

constexpr has to be consistent for variables and functions and
everything else.

Can you do it all with const, while retaining backward compatibility of
programs that don't know anything about the new constexpr meaning
of const?

I am deeply skeptical.
Thiago Adams
2024-10-13 21:12:21 UTC
Permalink
Post by Thiago Adams
What I am suggesting again is remove the keyword constexpr. make const
do that.
Related:

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3333.htm


I believe clang is already extending const power in more scenarios.

https://godbolt.org/z/h1ha5jfPn

struct X{
int i;
};

int main()
{
const struct X x2 = (struct X){.i=1};
static_assert(x2.i == 1);
}


https://godbolt.org/z/EW797PjEq
struct X{
int i;
};

int main()
{
const int a[] = {1, 2};
const struct X x2 = (struct X){.i=a[0]};
static_assert(x2.i == 1);
}
Bart
2024-10-12 13:53:16 UTC
Permalink
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Anything you do with it could/should be done with const.
Even without const , one object like (struct point){.x=1, .y=0} is a
constant in my view.
So, for instance, no need for (constexpr struct point){.x=1, .y=0} here.
The VLA could have been the motivation for a new keyword, but I don’t
think it matters.
On the other hand, (static struct point){.x=1, .y=0} makes sense.
If constexpr were "no-storage" I think it would make sense but it is not.
It depends on what constexpr means. Does it mean an expression known at
compile-time? (Or at load-time when the expression refers to addresses
of static memory locations that will not change during the program's run.)

Or does it mean the expression will not change after it's mean assigned?

For example:

const int i = rand();
i = rand(); // not (directly) allowed

Further, if the const/constexr is in a loop, or anywhere in a function
where it can be encountered a million times, can the expression be
different each time? Example:

while (1) {
const i = rand();
constexpr j = rand(); // if legal
}

C has a problem with named constants, which are variously implemented
with #define, enum and const, none of which do the whole job, although
enum comes closest.

So where does constexpr fit into all that?

This table refers to examples like '#define A 100', 'eval {B=200}', and
'const int C=300'; Y is the desirable answer in each case:

#define enum const
Scope rules N Y Y
Any type Y N Y
& is an error Y Y N
Value fixed Y Y N (can be changed via casts)
Array bounds Y Y N (statics/module scope)
Array bounds Y Y N to avoid VLAs
Case labels Y Y N
Context free N Y Y (to do with macro expansion)
Fixed eval time Y Y Y

The last one is to do with how long it takes the compiler to evaluate
the expression, which is normally negligible.

'const int C=X' depends on how long X takes at runtime.

But 'constexpr int C=X' can depend on how long X takes at compile-time.

What does the column for constexpr look like for the other attributes?
Thiago Adams
2024-10-12 21:43:14 UTC
Permalink
Post by Bart
It depends on what constexpr means.
It means the initialization expression must be evaluated at compilation.
Also the declarator can be used in another expression as constant.

Sample
constexpr int a = 1;
constexpr int b = a+1;

But the expression is always something the compiler need to check if is
constant or not.

So, what I suggest is if the init expression is a constant expression
(something we know at compile time) then the declarator is real
constexpr (no need for a new keyword)

For instance:

const int a = 1;
const int b = a+1;


Even if not constant, the compiler can do at compile time.
for instance.
int a = 1+2;
So this has to be done anyway.
The only difference is that using 'a' cannot be used as constant in
another expression.
Bart
2024-10-13 09:52:55 UTC
Permalink
Post by Thiago Adams
Post by Bart
It depends on what constexpr means.
It means the initialization expression must be evaluated at compilation.
Also the declarator can be used in another expression as constant.
Sample
constexpr int a = 1;
constexpr int b = a+1;
But the expression is always something the compiler need to check if is
constant or not.
So, what I suggest is if the init expression is a constant expression
(something we know at compile time) then the declarator is real
constexpr (no need for a new keyword)
const int a = 1;
const int b = a+1;
Even if not constant, the compiler can do at compile time.
for instance.
int a = 1+2;
So this has to be done anyway.
The only difference is that using 'a' cannot be used as constant in
another expression.
So it looks like const/constexpr do different things, for example:


const int a = rand(); // OK
constexpr int b = rand(); // error

How about this:

static int x;
const int* p = &x; // OK
constexpr int* q = &x; // ??

q's value isn't known at compile-time.
Thiago Adams
2024-10-13 11:37:48 UTC
Permalink
Post by Thiago Adams
Post by Bart
It depends on what constexpr means.
It means the initialization expression must be evaluated at compilation.
Also the declarator can be used in another expression as constant.
Sample
constexpr int a = 1;
constexpr int b = a+1;
But the expression is always something the compiler need to check if
is constant or not.
So, what I suggest is if the init expression is a constant expression
(something we know at compile time) then the declarator is real
constexpr (no need for a new keyword)
const int a = 1;
const int b = a+1;
Even if not constant, the compiler can do at compile time.
for instance.
int a = 1+2;
So this has to be done anyway.
The only difference is that using 'a' cannot be used as constant in
another expression.
  const int a = rand();              // OK
  constexpr int b = rand();          // error
Yes.
constexpr is like - "require the initializer to be a constant
expression." But the compiler will have to check it anyway.

What I am suggesting is:

If the compiler is going to check anyway, after check, if the
initializer is a constant expression, then transfer this property
"compile time" to the variable automatically. Then no need for a new
keyword.

One justification for the usage of constexpr could be , if constexpr is
not present then we can skip this compile time check. But most C
compiler will do optimization anyway.
  static int x;
  const int* p = &x;                // OK
  constexpr int* q = &x;            // ??
q's value isn't known at compile-time.
Addresses can be only initialized with 0 in C.
constexpr int* q = 0; //ok
Bonita Montero
2024-10-13 11:49:31 UTC
Permalink
Post by Thiago Adams
Yes.
constexpr is like - "require the initializer to be a constant
expression." But the compiler will have to check it anyway.
I cannot understand why you are so militantly against this
new language feature that can be understood in 10 seconds.
Thiago Adams
2024-10-13 12:38:04 UTC
Permalink
Post by Bonita Montero
Post by Thiago Adams
Yes.
constexpr is like - "require the initializer to be a constant
expression." But the compiler will have to check it anyway.
I cannot understand why you are so militantly against this
new language feature that can be understood in 10 seconds.
I have seen code like this:

void func()
{
constexpr int c = 1;
f(c);
}

For some reason, people believe that adding constexpr will magically
improve optimization. In reality, it doesn't change anything compared to
const and often reflects a misunderstanding of how the compiler works.
As a result, I end up having to explain it. In this sense, constexpr is
viral and spreads confusion.
Bonita Montero
2024-10-13 12:58:24 UTC
Permalink
Post by Thiago Adams
Post by Bonita Montero
Post by Thiago Adams
Yes.
constexpr is like - "require the initializer to be a constant
expression." But the compiler will have to check it anyway.
I cannot understand why you are so militantly against this
new language feature that can be understood in 10 seconds.
void func()
{
   constexpr int c = 1;
   f(c);
}
For some reason, people believe that adding constexpr will magically
improve optimization. In reality, it doesn't change anything compared to
const and often reflects a misunderstanding of how the compiler works.
As a result, I end up having to explain it. In this sense, constexpr is
viral and spreads confusion.
constexpr doesn't hurt.
Thiago Adams
2024-10-13 13:09:29 UTC
Permalink
Post by Bonita Montero
Post by Thiago Adams
Post by Bonita Montero
Post by Thiago Adams
Yes.
constexpr is like - "require the initializer to be a constant
expression." But the compiler will have to check it anyway.
I cannot understand why you are so militantly against this
new language feature that can be understood in 10 seconds.
void func()
{
    constexpr int c = 1;
    f(c);
}
For some reason, people believe that adding constexpr will magically
improve optimization. In reality, it doesn't change anything compared
to const and often reflects a misunderstanding of how the compiler
works. As a result, I end up having to explain it. In this sense,
constexpr is viral and spreads confusion.
constexpr doesn't hurt.
It spreads confusion, and makes code incompatible with previous versions
of C "for free".
Bonita Montero
2024-10-13 13:14:32 UTC
Permalink
Post by Bonita Montero
Post by Thiago Adams
Post by Bonita Montero
Post by Thiago Adams
Yes.
constexpr is like - "require the initializer to be a constant
expression." But the compiler will have to check it anyway.
I cannot understand why you are so militantly against this
new language feature that can be understood in 10 seconds.
void func()
{
    constexpr int c = 1;
    f(c);
}
For some reason, people believe that adding constexpr will magically
improve optimization. In reality, it doesn't change anything compared
to const and often reflects a misunderstanding of how the compiler
works. As a result, I end up having to explain it. In this sense,
constexpr is viral and spreads confusion.
constexpr doesn't hurt.
It spreads confusion, ...
It can be understood in 10s.
... and makes code incompatible with previous versions of C "for free".
New improvements are always incompatible and there are mature C23
compilers.
Janis Papanagnou
2024-10-13 13:35:02 UTC
Permalink
Post by Bonita Montero
Post by Bonita Montero
constexpr doesn't hurt.
It spreads confusion, ...
It can be understood in 10s.
I doubt that. - If you need a technical term for some "internal"
requirement you typically need a lot of background information
that (usually?) is pointless to a programmer.

What do I (in my role as a solution programmer) gain from it?

In that role specifically, but also generally, I think that
everything that a programming language can do under the hood
should not be a (concept-)burden to the programmer.

(Note that I'm not arguing against it.)
Post by Bonita Montero
... and makes code incompatible with previous versions of C "for free".
New improvements are always incompatible and there are mature C23
compilers.
What do I (in my role as a solution programmer) gain from it?
Is it "necessary" (as the topic formulates it)?

Is it reasonable to subsume it with the "const" keyword, as the
OP suggests. - I am honestly asking, and interested in whether
that makes sense or not. (Yet I haven't seen a clear answer, or
maybe I have missed it.)

Janis
Bonita Montero
2024-10-13 13:47:29 UTC
Permalink
Post by Bonita Montero
It can be understood in 10s.
I doubt that. - ...
LOL
What do I (in my role as a solution programmer) gain from it?
More expressive code.
Janis Papanagnou
2024-10-13 14:33:57 UTC
Permalink
Post by Bonita Montero
Post by Bonita Montero
It can be understood in 10s.
I doubt that. - ...
LOL
What do I (in my role as a solution programmer) gain from it?
More expressive code.
This is not the least convincing. Since you seem to express only a
language/compiler-internal theme, not any application programmers'
demand.

Regarding "expressiveness" (on the programmer's level) the OP's
suggestion (to use "const") is fine already, and probably better
than introducing a new keyword thus (unnecessarily?) complicating
the matter. - That's why I (honestly) asked for a concrete gain,
to understand whether it's maybe necessary for reasons that are
not yet obvious (to me).

But I take your elusion concerning my question as a meta-answer
that there is no gain. So don't bother.

Janis
Bonita Montero
2024-10-13 14:41:42 UTC
Permalink
Post by Janis Papanagnou
This is not the least convincing. Since you seem to express only a
language/compiler-internal theme, not any application programmers'
demand.
I don't understand how people can argue so desperately against a
feature that is so simple and that makes the code more readable.
Thiago Adams
2024-10-13 14:52:11 UTC
Permalink
Post by Bonita Montero
Post by Janis Papanagnou
This is not the least convincing. Since you seem to express only a
language/compiler-internal theme, not any application programmers'
demand.
I don't understand how people can argue so desperately against a
feature that is so simple and that makes the code more readable.
C programmers care about C simplicity.
Bonita Montero
2024-10-13 15:14:42 UTC
Permalink
Post by Thiago Adams
Post by Bonita Montero
Post by Janis Papanagnou
This is not the least convincing. Since you seem to express only a
language/compiler-internal theme, not any application programmers'
demand.
I don't understand how people can argue so desperately against a
feature that is so simple and that makes the code more readable.
C programmers care about C simplicity.
Not at this level.
Janis Papanagnou
2024-10-13 15:03:08 UTC
Permalink
Post by Bonita Montero
Post by Janis Papanagnou
This is not the least convincing. Since you seem to express only a
language/compiler-internal theme, not any application programmers'
demand.
I don't understand how people can argue so desperately against a
feature that is so simple and that makes the code more readable.
I'm aware that you are obviously in battle-mode and thus completely
missed that I'm not "against a feature" but just try to understand
the rationale for that. - Again you evaded answering that question,
and I see my suspicion confirmed that there is no gain.

For me, writing int i = 0; and const int i = 0; is perfectly
readable, and (unnecessarily!) adding another keyword degrades
readability.

As a programmer I expect a compiler to be able to detect constant
expressions, I don't want to litter my program code with technical
constructs to individually tell - on a per-statement basis - the
compiler that a specific constant expression should be evaluated
during compile-time and not postponed to run-time. To support a
simple compiler I think it's okay to instruct him explicitly to
spend more effort pre-evaluating constant expressions, say be a
compiler option. But certainly not by spreading keywords across
the code thereby making the code _less readable_.

(And, as you can derive from what I wrote, I find '_Static_eval'
also not increasing readability.)

Janis
Bonita Montero
2024-10-13 15:19:40 UTC
Permalink
Post by Janis Papanagnou
For me, writing int i = 0; and const int i = 0; is perfectly
readable, and (unnecessarily!) adding another keyword degrades
readability.
The difference is that for local variable const can be overridden
since this const is only logical constness but not physical const-
ness. This minimalist mindset is simply no longer up to date and,
considering the simplicity of the feature, simply absurd.
Michael S
2024-10-13 13:06:45 UTC
Permalink
On Sun, 13 Oct 2024 09:38:04 -0300
Post by Thiago Adams
Post by Bonita Montero
Post by Thiago Adams
Yes.
constexpr is like - "require the initializer to be a constant
expression." But the compiler will have to check it anyway.
I cannot understand why you are so militantly against this
new language feature that can be understood in 10 seconds.
void func()
{
constexpr int c = 1;
f(c);
}
For some reason, people believe that adding constexpr will magically
improve optimization. In reality, it doesn't change anything compared
to const and often reflects a misunderstanding of how the compiler
works. As a result, I end up having to explain it. In this sense,
constexpr is viral and spreads confusion.
I see constexpr primarily as a way to enable use of functions from
math.h in static initializers.
Thiago Adams
2024-10-13 13:10:19 UTC
Permalink
Post by Michael S
On Sun, 13 Oct 2024 09:38:04 -0300
Post by Thiago Adams
Post by Bonita Montero
Post by Thiago Adams
Yes.
constexpr is like - "require the initializer to be a constant
expression." But the compiler will have to check it anyway.
I cannot understand why you are so militantly against this
new language feature that can be understood in 10 seconds.
void func()
{
constexpr int c = 1;
f(c);
}
For some reason, people believe that adding constexpr will magically
improve optimization. In reality, it doesn't change anything compared
to const and often reflects a misunderstanding of how the compiler
works. As a result, I end up having to explain it. In this sense,
constexpr is viral and spreads confusion.
I see constexpr primarily as a way to enable use of functions from
math.h in static initializers.
Maybe you are thinking in C++? C does not have compile time functions.
Michael S
2024-10-13 13:29:01 UTC
Permalink
On Sun, 13 Oct 2024 10:10:19 -0300
Post by Thiago Adams
Post by Michael S
On Sun, 13 Oct 2024 09:38:04 -0300
Post by Thiago Adams
Post by Bonita Montero
Post by Thiago Adams
Yes.
constexpr is like - "require the initializer to be a constant
expression." But the compiler will have to check it anyway.
I cannot understand why you are so militantly against this
new language feature that can be understood in 10 seconds.
void func()
{
constexpr int c = 1;
f(c);
}
For some reason, people believe that adding constexpr will
magically improve optimization. In reality, it doesn't change
anything compared to const and often reflects a misunderstanding
of how the compiler works. As a result, I end up having to explain
it. In this sense, constexpr is viral and spreads confusion.
I see constexpr primarily as a way to enable use of functions from
math.h in static initializers.
Maybe you are thinking in C++? C does not have compile time functions.
I'd expect that in the next standard a wide subset of math functions
would be allowed in constexp.
In C++ they become constexpr in C++23. If no unexpected difficulties
shows up in C++ then C would be next.
Thiago Adams
2024-10-13 13:50:04 UTC
Permalink
Post by Michael S
On Sun, 13 Oct 2024 10:10:19 -0300
Post by Thiago Adams
Post by Michael S
On Sun, 13 Oct 2024 09:38:04 -0300
Post by Thiago Adams
Post by Bonita Montero
Post by Thiago Adams
Yes.
constexpr is like - "require the initializer to be a constant
expression." But the compiler will have to check it anyway.
I cannot understand why you are so militantly against this
new language feature that can be understood in 10 seconds.
void func()
{
constexpr int c = 1;
f(c);
}
For some reason, people believe that adding constexpr will
magically improve optimization. In reality, it doesn't change
anything compared to const and often reflects a misunderstanding
of how the compiler works. As a result, I end up having to explain
it. In this sense, constexpr is viral and spreads confusion.
I see constexpr primarily as a way to enable use of functions from
math.h in static initializers.
Maybe you are thinking in C++? C does not have compile time functions.
I'd expect that in the next standard a wide subset of math functions
would be allowed in constexp.
In C++ they become constexpr in C++23. If no unexpected difficulties
shows up in C++ then C would be next.
Let´s say we have

double i = sin(1);

adding constexpr

constexpr double i = sin(1);

makes sin(1) to be evaluated in compile time.

**BUT**, I may want to compute sin(1) even without making i const.

double i = sin(1);

This shows another incoherence.

The desire of pre compute the function in compile time should not be
dependent of the declarator being const.

So, in this case I would create a _Static_eval.

double i = _Static_eval(sin(1));

This feature is not competing with const creating two ways of doing
something. (like constexpr is doing)


This is a complement to the language to force compile time computation
in cases the expression is not required to be a constant expression.
Keith Thompson
2024-10-18 23:54:57 UTC
Permalink
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.

Keep in mind that "const" doesn't mean "constant".

In C, "constant" means (roughly) evaluable at compile time. (And as a
noun, it refers to what many other languages call "literals".)

The "const" keyword means "read-only"; the object it applies to cannot
be modified after it's initialized. The fact that the spelling of
the "const" keyword is derived from the word "constant" has caused a
great deal of confusion. Spelling it as "readonly" rather than "const"
would have avoided most of that confusion.

As of C11, the "const" keyword *never* makes an identifer usable in a
context that requires a constant expression. Given the following:

const int foo = <initializer>;

foo is treated the same way whether the initializer is constant
(e.g., 42) or not (e.g., rand()).

It's unfortunate that C11 doesn't provide a convenient way to define an
identifier as a constant expression of any arbitrary type. Adding
constexpr in C23 addresses that problem.

C++ made what was, in my opinion, an unfortunate decision. Given:

const int foo = 42;
const int bar = rand();

the name foo is a constant expression, but bar is not. This feature
(hack, IMHO) was added to C++ at a time that constexpr did not yet
exist.

So in C11, it's easy to explain what "const" means, but in C++ it's more
difficult because of that special-case rule.

"const" and "constexpr" do very different things. Conflating those into
a single keyword is not helpful. It might make the language easier to
use in some cases, but it makes it harder to explain. Spelling "const"
as "readonly" would have been an improvement, but it's far too late to
do that.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Bonita Montero
2024-10-19 07:18:37 UTC
Permalink
The "const" keyword means "read-only"; ...
A global const variable isn't even read-only, i.e. it's value is
assumed to be static and never changed. The compiler never reads
it but uses the constant which is assigned as an immediate value.
I.e. if your platform allows you to change-the value through
casting the updated value is never reflected in the other code.
Thiago Adams
2024-10-19 15:18:04 UTC
Permalink
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr", would
create problems?

The sample I know is VLA.

const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.


But this is not enough to convince me because it is better not to be a
VLA here.
Michael S
2024-10-19 16:53:05 UTC
Permalink
On Sat, 19 Oct 2024 12:18:04 -0300
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to be
a VLA here.
const int c = 2;
struct bar {
int a[c];
int b;
};
Thiago Adams
2024-10-19 19:35:37 UTC
Permalink
Post by Michael S
On Sat, 19 Oct 2024 12:18:04 -0300
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to be
a VLA here.
const int c = 2;
struct bar {
int a[c];
int b;
};
Yes, but in this case, you're changing something that was previously an
error into something that now works.
Keith Thompson
2024-10-19 21:49:55 UTC
Permalink
Post by Thiago Adams
Post by Michael S
On Sat, 19 Oct 2024 12:18:04 -0300
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to be
a VLA here.
const int c = 2;
struct bar {
int a[c];
int b;
};
Yes, but in this case, you're changing something that was previously
an error into something that now works.
Or you can change something that's an error into something that works in
C23 by typing "constexpr" rather than "const".
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Bart
2024-10-19 17:22:11 UTC
Permalink
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to be a
VLA here.
What practical difference would it make?  Can you think of any
difference between local variables "a" and "b" defined like this?
    enum { n = 2 };
    const int c = n;
    int a[c];
    int b[n];
Can you show any situation where you could use "a" and not "b", or vice
versa, or where the meaning would be different?  Can you show any
compiler that treats them differently in code generation (assuming a
compiler that supports enough of C99 to allow it)?
I know of no differences there.  That is enough to convince me that it
doesn't matter in the slightest whether it is technically a VLA or not.
I can give examples where a compiler won't work, or it will generate
different code, but you won't execpt it because you won't recognise the
compiler, or will dismiss it, or will dismiss even gcc because
optimisations aren't used.

If it will always be gcc-O2 or higher, and it is an example just like
these (so inside a function), then probably it will generate the same code.

But that's a lot of 'if's.

Where the code is different, then gcc on Windows for example likes to
generate a call to __chkstack() (to incrementally increase the stack a
page at a time in case it skips a page for a large allocation).
David Brown
2024-10-20 10:40:56 UTC
Permalink
Post by Bart
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to be
a VLA here.
What practical difference would it make?  Can you think of any
difference between local variables "a" and "b" defined like this?
     enum { n = 2 };
     const int c = n;
     int a[c];
     int b[n];
Can you show any situation where you could use "a" and not "b", or
vice versa, or where the meaning would be different?  Can you show any
compiler that treats them differently in code generation (assuming a
compiler that supports enough of C99 to allow it)?
I know of no differences there.  That is enough to convince me that it
doesn't matter in the slightest whether it is technically a VLA or not.
I can give examples where a compiler won't work, or it will generate
different code, but you won't execpt it because you won't recognise the
compiler, or will dismiss it, or will dismiss even gcc because
optimisations aren't used.
I know there are compilers that don't support VLAs at all - that's fair
enough (and that's why I specifically mentioned it). We can expect that
compilers that can't handle VLAs at all will not support C23 constexpr,
or any suggested C++ style extensions to the semantics of "const".

If you have an example of a compiler that /does/ support VLAs, but
generates different code for "a" and "b" above, then it would be
interesting to hear about it. I will put a lot more weight on its
relevance if it is a mainstream or established compiler (it is a big
advantage if it is on godbolt.org), and one that does at least some
level of optimisation. (For compilers that have no optimisation, or
where optimisation is disabled, code quality really doesn't matter
anyway.) Single user compilers, on the other hand, have little
relevance beyond that one user, and therefore do not matter much.
Post by Bart
If it will always be gcc-O2 or higher, and it is an example just like
these (so inside a function), then probably it will generate the same code.
But that's a lot of 'if's.
Where the code is different, then gcc on Windows for example likes to
generate a call to __chkstack() (to incrementally increase the stack a
page at a time in case it skips a page for a large allocation).
Not with -O1.
Keith Thompson
2024-10-20 18:28:08 UTC
Permalink
David Brown <***@hesbynett.no> writes:
[...]
Post by David Brown
I know there are compilers that don't support VLAs at all - that's
fair enough (and that's why I specifically mentioned it). We can
expect that compilers that can't handle VLAs at all will not support
C23 constexpr, or any suggested C++ style extensions to the semantics
of "const".
Why would we expect that?

IIRC, Microsoft has decided not to support VLAs in its C compiler. If
they chose not to support constexpr, they could not claim C23 conformance.

[...]
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Opus
2024-10-21 01:02:07 UTC
Permalink
Post by Keith Thompson
[...]
Post by David Brown
I know there are compilers that don't support VLAs at all - that's
fair enough (and that's why I specifically mentioned it). We can
expect that compilers that can't handle VLAs at all will not support
C23 constexpr, or any suggested C++ style extensions to the semantics
of "const".
Why would we expect that?
IIRC, Microsoft has decided not to support VLAs in its C compiler. If
they chose not to support constexpr, they could not claim C23 conformance.
Indeed. From the working draft I have of C23, while VLAs are optional,
constexpr is not as far as I can tell.

MS has a long history of being reluctant to be compliant with anything
past C89 - it took them ages to finally support C99, and after that,
they added strictly what was not optional from what I see.

More generally speaking, it looks like MS hasn't really cared about C
ever since the late 90's - early 2000's where they entirely focused on
C++. The Windows API is still C in itself for the most part, but it
doesn't require anything past C89 (again that I know of / remember).
Ditto for drivers.

So I don't think there is any internal incentive to keep up with C
standards, except for the strict minimum so that developers can't say
that MSVC is completely obsolete.

Regarding const vs constexpr, it looks like some people have a hard time
understanding the concept of not breaking existing behavior, which has
been one of C's strong points and largely explains why it's still being
used today. And as I understand, one argument was that const should be
constexpr in some contexts where it's considered "obvious" (but not in
others). Context-dependent keywords are not a fantastic idea.

Now may people tend to conflate 'constants' with 'literals' in C. And
don't realize that a const-qualified variable is still a 'variable', not
a 'constant' in the usual sense in CS. I personally think constexpr is a
welcome addition in C. The naming may be questionable, or not. Sure it
was borrowed from C++. From what I know, there has been a rule between
the C and the C++ standard committees for a while, that using different
naming and keywords for what's the same feature in the two languages
should be avoided. And I guess it makes sense.
David Brown
2024-10-21 06:40:01 UTC
Permalink
Post by Keith Thompson
[...]
Post by David Brown
I know there are compilers that don't support VLAs at all - that's
fair enough (and that's why I specifically mentioned it). We can
expect that compilers that can't handle VLAs at all will not support
C23 constexpr, or any suggested C++ style extensions to the semantics
of "const".
Why would we expect that?
IIRC, Microsoft has decided not to support VLAs in its C compiler. If
they chose not to support constexpr, they could not claim C23 conformance.
MS is in a somewhat different position than other C compiler vendors.
They decided - for various reasons - not to support C99 other than parts
that had direct correspondence with C++ features. Without having
followed any of the proceedings, I suspect the reason VLAs are optional
in C23 is because MS wants to avoid adding more than they have to before
being able to jump to (approximate) C23 conformance. "constexpr" will
be relatively easy for them, as they have it in C++ already.

(I don't know how recently updated the cppreference page on C23 compiler
support is, but if it is accurate, MS has a long way to go before C23
conformance - if that is even their aim.)

Pretty much every other C compiler that aims for at least vague
conformance, AFAIK, has done so linearly through the standards versions.
Keith Thompson
2024-10-21 20:47:30 UTC
Permalink
David Brown <***@hesbynett.no> writes:
[...]
Post by David Brown
MS is in a somewhat different position than other C compiler
vendors. They decided - for various reasons - not to support C99 other
than parts that had direct correspondence with C++ features. Without
having followed any of the proceedings, I suspect the reason VLAs are
optional in C23 is because MS wants to avoid adding more than they
have to before being able to jump to (approximate) C23 conformance.
"constexpr" will be relatively easy for them, as they have it in C++
already.
Yes, Microsoft pretty much skipped over C99, but if I recall correctly
their current C compiler has reasonably good support for C11.

[...]
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Chris M. Thomasson
2024-10-21 21:20:38 UTC
Permalink
Post by Keith Thompson
[...]
Post by David Brown
MS is in a somewhat different position than other C compiler
vendors. They decided - for various reasons - not to support C99 other
than parts that had direct correspondence with C++ features. Without
having followed any of the proceedings, I suspect the reason VLAs are
optional in C23 is because MS wants to avoid adding more than they
have to before being able to jump to (approximate) C23 conformance.
"constexpr" will be relatively easy for them, as they have it in C++
already.
Yes, Microsoft pretty much skipped over C99, but if I recall correctly
their current C compiler has reasonably good support for C11.
Last time I checked it did not have full support for C11 threads.
Post by Keith Thompson
[...]
Kaz Kylheku
2024-10-22 02:43:39 UTC
Permalink
Post by Chris M. Thomasson
Post by Keith Thompson
[...]
Post by David Brown
MS is in a somewhat different position than other C compiler
vendors. They decided - for various reasons - not to support C99 other
than parts that had direct correspondence with C++ features. Without
having followed any of the proceedings, I suspect the reason VLAs are
optional in C23 is because MS wants to avoid adding more than they
have to before being able to jump to (approximate) C23 conformance.
"constexpr" will be relatively easy for them, as they have it in C++
already.
Yes, Microsoft pretty much skipped over C99, but if I recall correctly
their current C compiler has reasonably good support for C11.
Last time I checked it did not have full support for C11 threads.
It's a pointless wrapper for POSIX threads, which differ from Windows
threads.

There is no reason to use it. Wherever POSIX threads are not found,
you can just implement *that* or find an implementation, or a
a subset that is good enough for your needs.

POSIX threads are no more or less standard than ISO C threads.
It is a gratuitous duplication.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Chris M. Thomasson
2024-10-22 19:18:04 UTC
Permalink
Post by Kaz Kylheku
Post by Chris M. Thomasson
Post by Keith Thompson
[...]
Post by David Brown
MS is in a somewhat different position than other C compiler
vendors. They decided - for various reasons - not to support C99 other
than parts that had direct correspondence with C++ features. Without
having followed any of the proceedings, I suspect the reason VLAs are
optional in C23 is because MS wants to avoid adding more than they
have to before being able to jump to (approximate) C23 conformance.
"constexpr" will be relatively easy for them, as they have it in C++
already.
Yes, Microsoft pretty much skipped over C99, but if I recall correctly
their current C compiler has reasonably good support for C11.
Last time I checked it did not have full support for C11 threads.
It's a pointless wrapper for POSIX threads, which differ from Windows
threads.
There is no reason to use it. Wherever POSIX threads are not found,
you can just implement *that* or find an implementation, or a
a subset that is good enough for your needs.
POSIX threads are no more or less standard than ISO C threads.
It is a gratuitous duplication.
The only compiler that I found that has full support for C11 threads,
atomics and membars was PellesC. The last time I checked MSVC for full
support was around a year and a half ago.

http://www.smorgasbordet.com/pellesc

They had some issues with some atomics that I pointed out:

https://forum.pellesc.de/index.php?topic=7167.msg27217#msg27217

https://forum.pellesc.de/index.php?topic=7311.msg27764#msg27764
Thiago Adams
2024-10-19 19:41:25 UTC
Permalink
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to be a
VLA here.
What practical difference would it make?
I don't see any practical difference. In theory, the generated code
could be different, but I'm arguing that this doesn't really matter and,
consequently, it's not a good reason to differentiate between const and
constexpr.
Keith Thompson
2024-10-19 21:48:46 UTC
Permalink
Post by Thiago Adams
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to
be a VLA here.
What practical difference would it make?
I don't see any practical difference. In theory, the generated code
could be different, but I'm arguing that this doesn't really matter
and, consequently, it's not a good reason to differentiate between
const and constexpr.
My reasons for not wanting `const int c = 2;` to make c a constant
expression have nothing to do with any theoretical difference in
generated code.

My reason is that "const" and "constant" are two almost entirely
distinct concepts. Conflating them makes the language more confusing.
Making the name of a "const" object a constant expression adds no new
capabilities beyone what we already have with "constexpr".

Though the C23 standard hasn't yet been officially released, it's too
late to make any substantive changes. C23 *will* have constexpr, and
*will not* treat const-qualified objects as constants.

If I want a name for a constant expression of type int, I can (in C23)
use "constexpr", which clearly expresses that intent. Using "const"
instead, in all versions of C up to and including C23, will result in
compile-time errors.

Let's pretend that when "const" was introduced in C89, it was spelled
"readonly", which more closely reflects its meaning. Would you suggest
that

readonly int n = 42;

should make n a constant expression?

What you propose would make n a constant expression if and only if its
initializer is constant. In C23, n is a constant expression if and only
if n is defined with "constexpr". If you add "constexpr" to a
declaration whose initializer is not a constant expression, it will be
rejected.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Thiago Adams
2024-10-19 22:49:58 UTC
Permalink
Post by Keith Thompson
Post by Thiago Adams
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to
be a VLA here.
What practical difference would it make?
I don't see any practical difference. In theory, the generated code
could be different, but I'm arguing that this doesn't really matter
and, consequently, it's not a good reason to differentiate between
const and constexpr.
My reasons for not wanting `const int c = 2;` to make c a constant
expression have nothing to do with any theoretical difference in
generated code.
My reason is that "const" and "constant" are two almost entirely
distinct concepts. Conflating them makes the language more confusing.
Making the name of a "const" object a constant expression adds no new
capabilities beyone what we already have with "constexpr".
I see some differences but not enough to justify a new keyword and I
think it also generates confusion. So it is a matter of choosing what
that of confusion we want.

For instance, in file scope,

const int a = 1;
constexpr int b =1;

In both cases, because it is file scope, a and b need to be initialized
with constant expressions. I don´t see anything more special in b
compared with a to make any distinction.
Post by Keith Thompson
Though the C23 standard hasn't yet been officially released, it's too
late to make any substantive changes. C23 *will* have constexpr, and
*will not* treat const-qualified objects as constants.
clang is already doing that (Allowing constant variable be used in
compile time). But It may be removed it in the future.
and I understand constexpr is already inside the C23.
Post by Keith Thompson
If I want a name for a constant expression of type int, I can (in C23)
use "constexpr", which clearly expresses that intent. Using "const"
instead, in all versions of C up to and including C23, will result in
compile-time errors.
Let's pretend that when "const" was introduced in C89, it was spelled
"readonly", which more closely reflects its meaning. Would you suggest
that
readonly int n = 42;
should make n a constant expression?
What you propose would make n a constant expression if and only if its
initializer is constant.
Yes, one of my points is that compilers will have to check whether the
initializer is a constant expression anyway. constexpr isn’t helping the
compiler or telling it something it doesn’t already know. It’s just
telling the compiler to do something it likely would do anyway, even for
local variables. So, the absence of constexpr is essentially telling the
compiler to ignore something it already knows and preventing existing
code from being handled at compile time

Consider:

const int c = 2;
int a = 0;
a = 1/(c-2);


The division by zero (c-2) will not be handled at compile time. Changing to:

constexpr int c = 2;
int a = 0;
a = 1/(c-2);

it will catch this even without flow analysis.

So, again, I don´t see a reason for not doing the same analysis using
const or allowing const variables be used in constant expressions.
Post by Keith Thompson
In C23, n is a constant expression if and only
if n is defined with "constexpr". If you add "constexpr" to a
declaration whose initializer is not a constant expression, it will be
rejected.
It seems like an artificial limitation has been introduced instead of
generalizing const.
Keith Thompson
2024-10-20 04:08:10 UTC
Permalink
[...]
Post by Thiago Adams
Post by Keith Thompson
My reasons for not wanting `const int c = 2;` to make c a constant
expression have nothing to do with any theoretical difference in
generated code.
My reason is that "const" and "constant" are two almost entirely
distinct concepts. Conflating them makes the language more confusing.
Making the name of a "const" object a constant expression adds no new
capabilities beyone what we already have with "constexpr".
I see some differences but not enough to justify a new keyword and I
think it also generates confusion. So it is a matter of choosing what
that of confusion we want.
But the new keyword already exists, and will be part of the language for
years. Removing the constexpr keyword will not be possible, because
doing so would break existing code.
Post by Thiago Adams
For instance, in file scope,
const int a = 1;
constexpr int b =1;
In both cases, because it is file scope, a and b need to be
initialized with constant expressions. I don´t see anything more
special in b compared with a to make any distinction.
As of C23, you're right. But what if a future C standard allows
non-constant initializers for file-scope object (as C++ already does)?
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Michael S
2024-10-20 11:59:06 UTC
Permalink
On Sat, 19 Oct 2024 21:08:10 -0700
Post by Keith Thompson
Post by Thiago Adams
For instance, in file scope,
const int a = 1;
constexpr int b =1;
In both cases, because it is file scope, a and b need to be
initialized with constant expressions. I don´t see anything more
special in b compared with a to make any distinction.
As of C23, you're right. But what if a future C standard allows
non-constant initializers for file-scope object (as C++ already does)?
You mean, initializers by arbitrary user code running before main?
Hopefully, it would never happen. Too much against the virtue of C.
Thiago Adams
2024-10-20 12:22:32 UTC
Permalink
Post by Keith Thompson
[...]
Post by Thiago Adams
Post by Keith Thompson
My reasons for not wanting `const int c = 2;` to make c a constant
expression have nothing to do with any theoretical difference in
generated code.
My reason is that "const" and "constant" are two almost entirely
distinct concepts. Conflating them makes the language more confusing.
Making the name of a "const" object a constant expression adds no new
capabilities beyone what we already have with "constexpr".
I see some differences but not enough to justify a new keyword and I
think it also generates confusion. So it is a matter of choosing what
that of confusion we want.
But the new keyword already exists, and will be part of the language for
years. Removing the constexpr keyword will not be possible, because
doing so would break existing code.
Yes. But const can be improved and we can just ignore constexpr.

Just to show one extra difference from constexpr

we have an error here

//'constexpr' initializer not representable in type of object
constexpr unsigned char c= 1234;

with const it is a warning. But again I don't think is is enough to
justify constexpr.
Post by Keith Thompson
Post by Thiago Adams
For instance, in file scope,
const int a = 1;
constexpr int b =1;
In both cases, because it is file scope, a and b need to be
initialized with constant expressions. I don´t see anything more
special in b compared with a to make any distinction.
As of C23, you're right. But what if a future C standard allows
non-constant initializers for file-scope object (as C++ already does)?
Then it could have initialization order problem..and C does not have
exceptions to report error in initialization..
What C could have is compile time functions.

const int i = f();

I think this situation can be automatic, the compiler will try to
evaluate f at compile time because there is no other alternative.
Bonita Montero
2024-10-22 08:02:01 UTC
Permalink
Post by Thiago Adams
//'constexpr' initializer not representable in type of object
constexpr unsigned char c= 1234;
with const it is a warning. ...
Good that we have constexpr now.
Thiago Adams
2024-10-22 12:48:11 UTC
Permalink
Post by Bonita Montero
Post by Thiago Adams
//'constexpr' initializer not representable in type of object
constexpr unsigned char c= 1234;
with const it is a warning. ...
Good that we have constexpr now.
I think a more generic feature would be to have a standard way of
promoting selected warnings to errors. This would avoid stacking
features with small differences, such as treating constexpr as a special
case compared to other constant expressions in C.
Vir Campestris
2024-10-26 14:07:05 UTC
Permalink
Post by Thiago Adams
I think a more generic feature would be to have a standard way of
promoting selected warnings to errors. This would avoid stacking
features with small differences, such as treating constexpr as a special
case compared to other constant expressions in C.
I have in the past had coding standards that require you to fix all
warnings. After all, sometimes they do matter.

IIRC we had a compiler that had a "treat warnings as errors" parameter.

Andy
James Kuyper
2024-10-26 15:08:09 UTC
Permalink
Post by Vir Campestris
Post by Thiago Adams
I think a more generic feature would be to have a standard way of
promoting selected warnings to errors. This would avoid stacking
features with small differences, such as treating constexpr as a special
case compared to other constant expressions in C.
I have in the past had coding standards that require you to fix all
warnings. After all, sometimes they do matter.
I disapprove of that policy. A conforming implementation is free to warn
about anything, even about your failure to use taboo words as
identifiers. While that's a deliberately silly example, I've seen a fair
number of warnings that had little or no justification.
The purpose of warnings is to tell you that there might be a problem. If
the compiler is certain that there's a problem, it should generate an
error message, not a warning. Therefore, treating warnings as if they
were error messages means that you're not doing your job, as the
developer, to determine whether or not the code is actually problematic.
Janis Papanagnou
2024-10-26 18:28:12 UTC
Permalink
Post by James Kuyper
Post by Vir Campestris
I have in the past had coding standards that require you to fix all
warnings. After all, sometimes they do matter.
I disapprove of that policy. A conforming implementation is free to warn
about anything, even about your failure to use taboo words as
identifiers. While that's a deliberately silly example, I've seen a fair
number of warnings that had little or no justification.
The purpose of warnings is to tell you that there might be a problem. If
the compiler is certain that there's a problem, it should generate an
error message, not a warning. Therefore, treating warnings as if they
were error messages means that you're not doing your job, as the
developer, to determine whether or not the code is actually problematic.
We had such a null-warning policy as well (in a C++ context) and it
served us well.

But I agree that it depends (besides on the language) also on the
types of emitted warnings (and on the compilers used, where you
typically can also control types of emitted warnings and adjust the
default settings appropriately).

In my book it's better to respect warnings in the first place before
deciding to [sophisticatedly] disable any of them, or, while not have
them disabled, to have them inspected on every compile run (until you
ignore them uninspected due to boredom). It's especially important if
you're working with a team of programmers with manifold skill levels.
And for automated build processes we wanted a reliable binary decision
("pass" or "fail", and not "maybe"). It's probably even more an issue
in multi-platform/multi-compiler/multi-teams projects (which was our
typical project setting).

Janis
Scott Lurndal
2024-10-26 19:37:08 UTC
Permalink
Post by Janis Papanagnou
Post by James Kuyper
Post by Vir Campestris
I have in the past had coding standards that require you to fix all
warnings. After all, sometimes they do matter.
I disapprove of that policy. A conforming implementation is free to warn
about anything, even about your failure to use taboo words as
identifiers. While that's a deliberately silly example, I've seen a fair
number of warnings that had little or no justification.
The purpose of warnings is to tell you that there might be a problem. If
the compiler is certain that there's a problem, it should generate an
error message, not a warning. Therefore, treating warnings as if they
were error messages means that you're not doing your job, as the
developer, to determine whether or not the code is actually problematic.
We had such a null-warning policy as well (in a C++ context) and it
served us well.
Yes, we have a similar policy. Works well. In the odd case where
one cannot eliminate the warning, a simple compiler option to not
test that particulary condition for that particular compilation unit
is a straightforward solution.
Tim Rentsch
2024-10-27 04:58:46 UTC
Permalink
Post by Scott Lurndal
Post by Janis Papanagnou
Post by Vir Campestris
I have in the past had coding standards that require you to fix all
warnings. After all, sometimes they do matter.
I disapprove of that policy. A conforming implementation is free to warn
about anything, even about your failure to use taboo words as
identifiers. While that's a deliberately silly example, I've seen a fair
number of warnings that had little or no justification.
The purpose of warnings is to tell you that there might be a problem. If
the compiler is certain that there's a problem, it should generate an
error message, not a warning. Therefore, treating warnings as if they
were error messages means that you're not doing your job, as the
developer, to determine whether or not the code is actually problematic.
We had such a null-warning policy as well (in a C++ context) and it
served us well.
Yes, we have a similar policy. Works well. In the odd case where
one cannot eliminate the warning, a simple compiler option to not
test that particulary condition for that particular compilation unit
is a straightforward solution.
So the actual policy is to fix all warnings except in
cases where it's inconvenient to fix them?
Scott Lurndal
2024-10-27 17:22:52 UTC
Permalink
Post by Tim Rentsch
Post by Scott Lurndal
Post by Janis Papanagnou
Post by Vir Campestris
I have in the past had coding standards that require you to fix all
warnings. After all, sometimes they do matter.
I disapprove of that policy. A conforming implementation is free to warn
about anything, even about your failure to use taboo words as
identifiers. While that's a deliberately silly example, I've seen a fair
number of warnings that had little or no justification.
The purpose of warnings is to tell you that there might be a problem. If
the compiler is certain that there's a problem, it should generate an
error message, not a warning. Therefore, treating warnings as if they
were error messages means that you're not doing your job, as the
developer, to determine whether or not the code is actually problematic.
We had such a null-warning policy as well (in a C++ context) and it
served us well.
Yes, we have a similar policy. Works well. In the odd case where
one cannot eliminate the warning, a simple compiler option to not
test that particulary condition for that particular compilation unit
is a straightforward solution.
So the actual policy is to fix all warnings except in
cases where it's inconvenient to fix them?
No, I never said that. Our C++ application has just under
three million SLOC. There was one broken version of g++
we had to support that was warning about legal code, and
for that version of the compiler, we suppressed the warning
individually.
Tim Rentsch
2024-11-04 03:06:30 UTC
Permalink
Post by Scott Lurndal
Post by Tim Rentsch
Post by Janis Papanagnou
Post by Vir Campestris
I have in the past had coding standards that require you to fix
all warnings. After all, sometimes they do matter.
I disapprove of that policy. A conforming implementation is
free to warn about anything, even about your failure to use
taboo words as identifiers. While that's a deliberately silly
example, I've seen a fair number of warnings that had little or
no justification. The purpose of warnings is to tell you that
there might be a problem. If the compiler is certain that
there's a problem, it should generate an error message, not a
warning. Therefore, treating warnings as if they were error
messages means that you're not doing your job, as the developer,
to determine whether or not the code is actually problematic.
We had such a null-warning policy as well (in a C++ context) and
it served us well.
Yes, we have a similar policy. Works well. In the odd case where
one cannot eliminate the warning, a simple compiler option to not
test that particulary condition for that particular compilation
unit is a straightforward solution.
So the actual policy is to fix all warnings except in
cases where it's inconvenient to fix them?
No, I never said that.
I didn't say you did. I asked a question because I didn't see
any clear statement of what the policy is that was being
followed. And I still haven't.

David Brown
2024-10-27 14:24:34 UTC
Permalink
Post by Vir Campestris
Post by Thiago Adams
I think a more generic feature would be to have a standard way of
promoting selected warnings to errors. This would avoid stacking
features with small differences, such as treating constexpr as a
special case compared to other constant expressions in C.
I have in the past had coding standards that require you to fix all
warnings. After all, sometimes they do matter.
I disapprove of that policy. A conforming implementation is free to
warn about anything, even about your failure to use taboo words as
identifiers. While that's a deliberately silly example, I've seen a
fair number of warnings that had little or no justification. [...]
I expect that when people say "all warnings" they don't really mean
all warning conditions that compilers currently can test for, in
the sense of -Weverything in clang (and they certainly don't mean
any warning condition that is allowed to be tested, since as you
point out that is much too wide a circle to be useful). But by
saying "all warnings" the most important part of the information is
concealed, because we don't know what warning conditions are meant
to be included in "all warnings." I would happily agree to fix
"all warnings" if I get to choose which set of warning conditions
is covered. Conversely, I would never agree to fix "all warnings"
if someone else is doing the choosing and doesn't define what set
of warning conditions is to be tested.
Exactly.

The choice of "all warnings" for a particular project (or subproject)
should be an active decision, going along with decisions of which
language to use, which version of the standards to use, which extensions
to allow, which coding standard to follow, and so on. These are,
obviously, related decisions.
Kaz Kylheku
2024-10-28 06:13:21 UTC
Permalink
Post by James Kuyper
Post by Vir Campestris
Post by Thiago Adams
I think a more generic feature would be to have a standard way of
promoting selected warnings to errors. This would avoid stacking
features with small differences, such as treating constexpr as a special
case compared to other constant expressions in C.
I have in the past had coding standards that require you to fix all
warnings. After all, sometimes they do matter.
I disapprove of that policy. A conforming implementation is free to warn
about anything, even about your failure to use taboo words as
identifiers.
I also follow that and it's been that way pretty much everywhere
I have worked, at least recently.

But not literally like that.

Of course, you control which warnings are in effect, and fix those.

You disable silly warnings you disagree with, rather than fix them.

The business of deciding what diagnostics are going to be used and which
are not is a separate activity. Usually most of the activity in this are
occurs when there is a compiler change, such as an upgrade.

The newer or different compiler offser some diagnostics which trigger in
the code, and for each, the squelch-or-fix decision has to be made.

It's not always an easy decision, because the value, or lack thereof, of
a diagnostic is not always apaprent from one situation in which it goes
off. Some diagnostics can be wortwhile in spite of a significant false
positive rate.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Thiago Adams
2024-10-28 11:58:26 UTC
Permalink
Post by Vir Campestris
Post by Thiago Adams
I think a more generic feature would be to have a standard way of
promoting selected warnings to errors. This would avoid stacking
features with small differences, such as treating constexpr as a special
case compared to other constant expressions in C.
I have in the past had coding standards that require you to fix all
warnings. After all, sometimes they do matter.
I believe warnings in code should be treated as alarms that require
acknowledgment.

For instance,

const unsigned char ch = 1234;

GCC:
warning: unsigned conversion from 'int' to 'unsigned char' changes value
from '1234' to '210' [-Woverflow]

The programmer might intend this behavior; in that case, the "alarm"
should be acknowledged.

I would like a portable (standardized) way to achieve this.
Kaz Kylheku
2024-10-29 05:04:35 UTC
Permalink
Post by Thiago Adams
I believe warnings in code should be treated as alarms that require
acknowledgment.
For instance,
const unsigned char ch = 1234;
warning: unsigned conversion from 'int' to 'unsigned char' changes value
from '1234' to '210' [-Woverflow]
The programmer might intend this behavior; in that case, the "alarm"
should be acknowledged.
I would like a portable (standardized) way to achieve this.
For conversion warnings, that portable way should ideally be a cast.

Any half-decent compiler should shut up if the conversion is
explicitly requested:

const unsigned char ch = (unsigned char) 1234;

If not, complain to the compiler developer.

It works this way for conversions that are constraint violations,
like between unlike pointers. Assign a pointer to a variable of
the wrong type, and there is a required diagnostic. With a cast,
the diagnostic is not required, and it would be irksome if there
still were one.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Thiago Adams
2024-10-29 12:16:52 UTC
Permalink
Post by Kaz Kylheku
Post by Thiago Adams
I believe warnings in code should be treated as alarms that require
acknowledgment.
For instance,
const unsigned char ch = 1234;
warning: unsigned conversion from 'int' to 'unsigned char' changes value
from '1234' to '210' [-Woverflow]
The programmer might intend this behavior; in that case, the "alarm"
should be acknowledged.
I would like a portable (standardized) way to achieve this.
For conversion warnings, that portable way should ideally be a cast.
Any half-decent compiler should shut up if the conversion is
const unsigned char ch = (unsigned char) 1234;
If not, complain to the compiler developer.
It works this way for conversions that are constraint violations,
like between unlike pointers. Assign a pointer to a variable of
the wrong type, and there is a required diagnostic. With a cast,
the diagnostic is not required, and it would be irksome if there
still were one.
Yes, in this case, using a cast is the way to go with current compilers.

But, the concept of "alarm acknowledgment" removes a specific warning
that must exist. It can be a safer alternative.

(I intend to show a general idea. There are likely better examples.)

Consider this function:


void f(int i) {
...
const unsigned char c = (unsigned char)i;
}


If someone changes the type of `i` to `unsigned char`, then the cast
becomes unnecessary:


void f(unsigned char ch) {
...
const unsigned char c = (unsigned char)ch;
}


With the "alarm acknowledgment" idea (I'll just invent a syntax
`[[!truncation]]`), we would get a warning if there is no actual
truncation to acknowledge. For example:


void f(unsigned char ch) {
...
const unsigned char c = (unsigned char)ch; [[!truncation]];
// Warning: there is no truncation to acknowledge.
}


The way GCC/Clang works today, we can disable some warning using pragma.


#pragma CAKE diagnostic push
#pragma CAKE diagnostic ignored "-Wenum-conversion"
...
...
#pragma CAKE diagnostic pop

The code represented by "..." may change, which could cause the warning
to disappear, making any ignored "-Wenum-conversion" directive
unnecessary noise. Additionally, we could mistakenly disable more
warnings than initially intended.

So the "alarm acknowledgment" can be a safer complement for the language.
Thiago Adams
2024-10-29 12:21:11 UTC
Permalink
On 29/10/2024 09:16, Thiago Adams wrote:

Edit to fix the sample

// Here we acknowledge the truncation
void f(int i) {
...
const unsigned char c = i; [[!truncation]];
}


// Warning: there is no truncation to acknowledge.
void f(unsigned char i) {
...
const unsigned char c = i; [[!truncation]];
}
David Brown
2024-10-29 14:13:16 UTC
Permalink
Post by Thiago Adams
Edit to fix the sample
// Here we acknowledge the truncation
void f(int i) {
    ...
    const unsigned char c = i; [[!truncation]];
}
// Warning: there is no truncation to acknowledge.
void f(unsigned char i) {
    ...
    const unsigned char c = i; [[!truncation]];
}
This should give you what you are asking for, if I have understood you
correctly:

#define truncate(type, value) \
_Generic((value), \
type : (void) 0, \
default : (type) value \
)



// OK
void f1(int i) {
const auto c = truncate(unsigned char, i);
}

// Error
void f1(unsigned char i) {
const auto c = truncate(unsigned char, i);
}


I am not at all convinced this is a good idea. I am /certainly/ not
convinced "truncate" is a good name - the general term, AFAIK, for a
conversion that might try to squeeze a large value into a smaller type
is "narrowing" rather than "truncating".

You could expand the idea further and have a "truncate" macro that
checks for bounds at run time or compile time (I'd make use of the gcc
extension __builtin_constant_p here, but there may be a fully standard
way to do this).
Thiago Adams
2024-10-29 14:46:46 UTC
Permalink
Post by David Brown
Post by Thiago Adams
Edit to fix the sample
// Here we acknowledge the truncation
void f(int i) {
     ...
     const unsigned char c = i; [[!truncation]];
}
// Warning: there is no truncation to acknowledge.
void f(unsigned char i) {
     ...
     const unsigned char c = i; [[!truncation]];
}
This should give you what you are asking for, if I have understood you
#define truncate(type, value) \
    _Generic((value), \
        type : (void) 0, \
        default : (type) value \
    )
// OK
void f1(int i) {
    const auto c = truncate(unsigned char, i);
}
// Error
void f1(unsigned char i) {
    const auto c = truncate(unsigned char, i);
}
I am not at all convinced this is a good idea.  I am /certainly/ not
convinced "truncate" is a good name - the general term, AFAIK, for a
conversion that might try to squeeze a large value into a smaller type
is "narrowing" rather than "truncating".
You could expand the idea further and have a "truncate" macro that
checks for bounds at run time or compile time (I'd make use of the gcc
extension __builtin_constant_p here, but there may be a fully standard
way to do this).
As I said,
Post by David Brown
(I intend to show a general idea. There are likely better examples.)
My objective was to show the concept of "warning acknowledge".

Name and syntax weren't important.

The solution for truncate you are proposing maybe is valid, but it is
for the specific case.
I think it is valid to think is specific cases and I can find more samples.
maybe if (condition) where the condition is constant expressions.
David Brown
2024-10-29 18:27:28 UTC
Permalink
Post by Thiago Adams
Post by David Brown
Post by Thiago Adams
Edit to fix the sample
// Here we acknowledge the truncation
void f(int i) {
     ...
     const unsigned char c = i; [[!truncation]];
}
// Warning: there is no truncation to acknowledge.
void f(unsigned char i) {
     ...
     const unsigned char c = i; [[!truncation]];
}
This should give you what you are asking for, if I have understood you
#define truncate(type, value) \
     _Generic((value), \
         type : (void) 0, \
         default : (type) value \
     )
// OK
void f1(int i) {
     const auto c = truncate(unsigned char, i);
}
// Error
void f1(unsigned char i) {
     const auto c = truncate(unsigned char, i);
}
I am not at all convinced this is a good idea.  I am /certainly/ not
convinced "truncate" is a good name - the general term, AFAIK, for a
conversion that might try to squeeze a large value into a smaller type
is "narrowing" rather than "truncating".
You could expand the idea further and have a "truncate" macro that
checks for bounds at run time or compile time (I'd make use of the gcc
extension __builtin_constant_p here, but there may be a fully standard
way to do this).
As I said,
Post by David Brown
(I intend to show a general idea. There are likely better examples.)
My objective was to show the concept of "warning acknowledge".
Name and syntax weren't important.
The solution for truncate you are proposing maybe is valid, but it is
for the specific case.
I think it is valid to think is specific cases and I can find more samples.
maybe if (condition) where the condition is constant expressions.
Well, there is already a syntax standardised for use for this kind of
thing - attributes. For example, marking a function declaration with
[[noreturn]] will turn off any warnings about the function failing to
return. Attributes are specifically for such additional information to
improve the compiler's knowledge (for the purposes of optimisation
and/or static error checking) without affecting the semantics of the code.

(I don't think there is a need for an attribute to disable a narrowing
initialisation, since a cast will do the job just fine, and I don't see
any need for a "warn about unnecessary cast" attribute. But attributes
could be used for a similar general idea.)

What would have been nice, perhaps, is if C had adopted the C++
semantics that "type x = { y };" is an error if it requires a narrowing
conversion, rather than leaving it up to the compiler to choose to have
a warning or not. But I think that would mean a similar unfortunate mix
of concepts to Keith's complaint about "const" in C++ - such an
initialisation will be a compile-time error in C++ if "y" is out of
range and is a constant expression, but not if it is not a constant
expression. (You do get a compile-time error in both languages if
narrowing changes the value for initialising a constexpr variable.)
Janis Papanagnou
2024-10-30 00:41:50 UTC
Permalink
[...] I am /certainly/ not
convinced "truncate" is a good name - the general term, AFAIK, for a
conversion that might try to squeeze a large value into a smaller type
is "narrowing" rather than "truncating".
Algol 68 has an operator called 'shorten' for that (which resembles
the 'long'/'short' type naming). - Just to throw in an alternative
name (which also fits to "C" with its [similar] long/short types).

Janis
Kaz Kylheku
2024-10-29 20:57:23 UTC
Permalink
Post by Thiago Adams
Post by Kaz Kylheku
Post by Thiago Adams
I believe warnings in code should be treated as alarms that require
acknowledgment.
For instance,
const unsigned char ch = 1234;
warning: unsigned conversion from 'int' to 'unsigned char' changes value
from '1234' to '210' [-Woverflow]
The programmer might intend this behavior; in that case, the "alarm"
should be acknowledged.
I would like a portable (standardized) way to achieve this.
For conversion warnings, that portable way should ideally be a cast.
Any half-decent compiler should shut up if the conversion is
const unsigned char ch = (unsigned char) 1234;
If not, complain to the compiler developer.
It works this way for conversions that are constraint violations,
like between unlike pointers. Assign a pointer to a variable of
the wrong type, and there is a required diagnostic. With a cast,
the diagnostic is not required, and it would be irksome if there
still were one.
Yes, in this case, using a cast is the way to go with current compilers.
But, the concept of "alarm acknowledgment" removes a specific warning
that must exist. It can be a safer alternative.
(I intend to show a general idea. There are likely better examples.)
void f(int i) {
...
const unsigned char c = (unsigned char)i;
}
If someone changes the type of `i` to `unsigned char`, then the cast
void f(unsigned char ch) {
...
const unsigned char c = (unsigned char)ch;
}
With the "alarm acknowledgment" idea (I'll just invent a syntax
`[[!truncation]]`), we would get a warning if there is no actual
void f(unsigned char ch) {
...
const unsigned char c = (unsigned char)ch; [[!truncation]];
// Warning: there is no truncation to acknowledge.
}
"I think truncation does not happen" is here logically equivalent to
the specific condition that ch is in the range 0 to UCHAR_MAX.

That can be asserted:

assert (0 <= ch && ch <= UCHAR_MAX);

If ch has the type unsigned char, then this condition is always
true.

We can think about a warning like that "controlling expression of assert
unconditionally true due to range of types", but it serves no purpose.
There is nothing wrong with asserting something that is always true.

When assertions are enabled, the compiler can use their predicates
to reason about the code and not warn about conditions that are
precluded by assertions being true.

You will find that this already happens in today's compilers,
and not due to assert being treated specially. The assertion
translates into something like

if (!(0 <= ch && ch <= UCHAR_MAX)) do {
__assert_fail("0 <= ch && ch <= UCHAR_MAX", "foo.c", 42);
} while (0)

where __assert_fail is annotated a function which does not return. From
the non-returning property of the function, the compiler can infer that
0 <= ch and ch <= UCHAR_MAX must be true after that statement.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Richard Harnden
2024-10-29 17:26:08 UTC
Permalink
Post by Thiago Adams
For instance,
const unsigned char ch = 1234;
warning: unsigned conversion from 'int' to 'unsigned char' changes value
from '1234' to '210' [-Woverflow]
The programmer might intend this behavior; in that case, the "alarm"
should be acknowledged.
If that is what you want, then why not simply say:
const unsigned char ch = 210;

Or change it to the char to a short (or int, long, etc).

?

It's a good and helpful warning. I cannot see why you'd want to ignore it.

Do you expect to remember that 1234 really equals 210 in five years time?
Thiago Adams
2024-10-29 17:48:29 UTC
Permalink
Post by Thiago Adams
For instance,
const unsigned char ch = 1234;
warning: unsigned conversion from 'int' to 'unsigned char' changes
value from '1234' to '210' [-Woverflow]
The programmer might intend this behavior; in that case, the "alarm"
should be acknowledged.
    const unsigned char ch = 210;
Or change it to the char to a short (or int, long, etc).
?
It's a good and helpful warning.  I cannot see why you'd want to ignore it.
Do you expect to remember that 1234 really equals 210 in five years time?
When I use a concrete example, people often assume I’m discussing a
specific case, even if I explicitly state that it’s just an example (and
this happens all the time).

Here’s the main idea: Sometimes, we have warnings in our code. I’m
proposing a feature that identifies warnings that necessary exists.

The issue with disabling warnings in specific code regions is that, if
the code is changed to remove the warning, the disable command often
isn’t removed. Additionally, with code modifications, we might
unintentionally end up disabling more warnings than originally intended.

I also presented a sample with cast.

For the *specific sample* of course there is an alternative of just
wring the final number.

Another sample:

In GCC

const int i = 1231231231231*123123123123123;

This is a warning about overflow. If the overflow is intentional, for
instance, to observe the final result, the programmer can choose to
dismiss the warning.
Tim Rentsch
2024-10-27 04:37:20 UTC
Permalink
Post by Vir Campestris
Post by Thiago Adams
I think a more generic feature would be to have a standard way of
promoting selected warnings to errors. This would avoid stacking
features with small differences, such as treating constexpr as a
special case compared to other constant expressions in C.
I have in the past had coding standards that require you to fix all
warnings. After all, sometimes they do matter.
Everyone agrees that all warnings should be fixed. Where people
differ is what set of warning conditions should be enabled.

At (or at least near) one end of the spectrum is -pedantic.

At the other end of the spectrum is -Weverything in clang. (I
confess I am sort of assuming that -Weverything includes every
warning condition known to man, which might not be the case. But
I trust people can understand what is meant by "-Weverything".)

I expect most people would advocate a point somewhere between the
two extremes. But there are different ideas about where that
point should be.

Whether warnings can or should be turned into errors is a
separate question. The first question is what set of warning
conditions should be enabled. A statement that all warnings
should be fixed is meaningless if there is no indication of
what warning conditions should be enabled.
David Brown
2024-10-27 14:32:32 UTC
Permalink
Post by Tim Rentsch
Post by Vir Campestris
Post by Thiago Adams
I think a more generic feature would be to have a standard way of
promoting selected warnings to errors. This would avoid stacking
features with small differences, such as treating constexpr as a
special case compared to other constant expressions in C.
I have in the past had coding standards that require you to fix all
warnings. After all, sometimes they do matter.
Everyone agrees that all warnings should be fixed. Where people
differ is what set of warning conditions should be enabled.
At (or at least near) one end of the spectrum is -pedantic.
Note that for most code, strict conformance to C standards is not a
major concern - most programs are at least somewhat platform specific or
compiler-specific. If that is the case, then it is a good thing to use
non-standard features if they make the code clearer or open the
possibility of more static checking.
Post by Tim Rentsch
At the other end of the spectrum is -Weverything in clang. (I
confess I am sort of assuming that -Weverything includes every
warning condition known to man, which might not be the case. But
I trust people can understand what is meant by "-Weverything".)
As I understand it, "-Weverything" was more intended for tests of the
compiler than an option anyone should use in practice. More realistic,
I think, would be "-Wall -Wextra" which enables several warnings that
many people would feel give a lot of hits on perfectly good code.
Post by Tim Rentsch
I expect most people would advocate a point somewhere between the
two extremes. But there are different ideas about where that
point should be.
Yes - and there /should/ be different ideas there.
Post by Tim Rentsch
Whether warnings can or should be turned into errors is a
separate question. The first question is what set of warning
conditions should be enabled. A statement that all warnings
should be fixed is meaningless if there is no indication of
what warning conditions should be enabled.
Agreed - deciding on the warnings to use is critical.

In my mind, the important aspect of turning warnings into errors is that
the won't be overlooked or forgotten. It's easy to miss warnings in the
middle of larger builds - errors are usually much harder to ignore
(intentionally or unintentionally).
Thiago Adams
2024-10-20 01:56:03 UTC
Permalink
Post by Keith Thompson
Let's pretend that when "const" was introduced in C89, it was spelled
"readonly", which more closely reflects its meaning. Would you suggest
that
readonly int n = 42;
should make n a constant expression?
I used to find const confusing, as it sometimes meant 'read-only' and
other times 'immutable.'
Now, it seems less confusing to me. When const is used with variables
that can be initialized (init-declarator), it acts as 'immutable,'
meaning the storage is constant.
In other contexts, like function parameters, const means 'read-only'
because we don’t know if the storage is constant or not.

It’s also interesting to note that constexpr acts as a storage
qualifier. What the compiler needs to know when evaluating an expression
at compile time, without depending on flow analysis, is the guarantee
that the object is immutable. This makes it safe to use the value it has
at initialization when the initialization is also a compile time expression.

const used in variables that can be initialized gives the compiler the
same guarantees.
Bonita Montero
2024-10-20 16:12:27 UTC
Permalink
Post by Thiago Adams
I used to find const confusing, as it sometimes meant 'read-only' and
other times 'immutable.'
Now, it seems less confusing to me. When const is used with variables
that can be initialized (init-declarator), it acts as 'immutable,'
meaning the storage is constant.
In other contexts, like function parameters, const means 'read-only'
because we don’t know if the storage is constant or not.
I'm asking myself what should be confusing with constexpr.
Post by Thiago Adams
It’s also interesting to note that constexpr acts as a storage
qualifier. What the compiler needs to know when evaluating an expression
at compile time, without depending on flow analysis, is the guarantee
that the object is immutable. This makes it safe to use the value it has
at initialization when the initialization is also a compile time expression.
const used in variables that can be initialized gives the compiler the
same guarantees.
David Brown
2024-10-20 10:45:46 UTC
Permalink
Post by Thiago Adams
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to be
a VLA here.
What practical difference would it make?
I don't see any practical difference. In theory, the generated code
could be different, but I'm arguing that this doesn't really matter and,
consequently, it's not a good reason to differentiate between const and
constexpr.
My point was that if there is no practical difference, then there is no
reason to object to the VLA.

You can't use this as a reason for arguing that it would have been
better for "const" in C to gain the features that are now in C23
"constexpr", because this use of "const" was already allowed in C99. So
the "const" vs "constexpr" discussion is an orthogonal issue - I was
asking specifically about your comment regarding your apparent dislike
of VLA's.
Bart
2024-10-20 11:23:41 UTC
Permalink
Post by David Brown
Post by Thiago Adams
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to be
a VLA here.
What practical difference would it make?
I don't see any practical difference. In theory, the generated code
could be different, but I'm arguing that this doesn't really matter
and, consequently, it's not a good reason to differentiate between
const and constexpr.
My point was that if there is no practical difference, then there is no
reason to object to the VLA.
I've seen endless exampples where people inadvertently created VLAs, and
where they are likely to less efficient.

It might start off like this:

const int n = 10;
int A[n];

Then they change something so that n is not evaluated until runtime
(maybe it's defined in terms of a parameter). Now the compiler will
silently generate less efficient code for a VLA, without giving the user
a chance to use an alternative.
Post by David Brown
You can't use this as a reason for arguing that it would have been
better for "const" in C to gain the features that are now in C23
"constexpr", because this use of "const" was already allowed in C99.  So
the "const" vs "constexpr" discussion is an orthogonal issue - I was
asking specifically about your comment regarding your apparent dislike
of VLA's.
The advantage of constexpr AIUI is that a non-constant initialiser for n
is not allowed.
David Brown
2024-10-20 11:36:51 UTC
Permalink
Post by Bart
Post by David Brown
Post by Thiago Adams
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to
be a VLA here.
What practical difference would it make?
I don't see any practical difference. In theory, the generated code
could be different, but I'm arguing that this doesn't really matter
and, consequently, it's not a good reason to differentiate between
const and constexpr.
My point was that if there is no practical difference, then there is
no reason to object to the VLA.
I've seen endless exampples where people inadvertently created VLAs, and
where they are likely to less efficient.
I can't say I have ever seem such as situation. But of course
experiences differ.
Post by Bart
    const int n = 10;
    int A[n];
Then they change something so that n is not evaluated until runtime
(maybe it's defined in terms of a parameter). Now the compiler will
silently generate less efficient code for a VLA, without giving the user
a chance to use an alternative.
Yes, a VLA where the size is not known at compile time will be less
efficient than when the size is fixed. It might still be a lot more
efficient than alternatives, such as using malloc(). I think VLAs -
with run-time sizes - have their uses, but you should be aware of when
you use them.
Post by Bart
Post by David Brown
You can't use this as a reason for arguing that it would have been
better for "const" in C to gain the features that are now in C23
"constexpr", because this use of "const" was already allowed in C99.
So the "const" vs "constexpr" discussion is an orthogonal issue - I
was asking specifically about your comment regarding your apparent
dislike of VLA's.
The advantage of constexpr AIUI is that a non-constant initialiser for n
is not allowed.
Yes, that is something I also see as an advantage.
Keith Thompson
2024-10-19 21:24:30 UTC
Permalink
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to be
a VLA here.
What practical difference would it make? Can you think of any
difference between local variables "a" and "b" defined like this?
enum { n = 2 };
const int c = n;
int a[c];
int b[n];
Can you show any situation where you could use "a" and not "b", or
vice versa, or where the meaning would be different? Can you show any
compiler that treats them differently in code generation (assuming a
compiler that supports enough of C99 to allow it)?
I know of no differences there. That is enough to convince me that it
doesn't matter in the slightest whether it is technically a VLA or
not.
VLAs are optional in C11 and later. A conforming implementation that
doesn't support VLAs will accept `int b[n];` and reject `int a[c];`.

`sizeof a` is not a constant expression, so it can't be used in a case
label or any other context that requires a constant expression. (If
`const int c = n;` made c a constant expression, this would not apply.)

Generated code for constructs that a compiler acccepts is likely to be
identical. For a VLA type with a non-constant length, the compiler must
implicitly store the size somehow. For a VLA type with a length that
the compiler can evaluate at compile time, the compiler is likely to
generate code equivalent to that for a non-VLA.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Thiago Adams
2024-10-19 22:13:30 UTC
Permalink
Post by Keith Thompson
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to be
a VLA here.
What practical difference would it make? Can you think of any
difference between local variables "a" and "b" defined like this?
enum { n = 2 };
const int c = n;
int a[c];
int b[n];
Can you show any situation where you could use "a" and not "b", or
vice versa, or where the meaning would be different? Can you show any
compiler that treats them differently in code generation (assuming a
compiler that supports enough of C99 to allow it)?
I know of no differences there. That is enough to convince me that it
doesn't matter in the slightest whether it is technically a VLA or
not.
VLAs are optional in C11 and later. A conforming implementation that
doesn't support VLAs will accept `int b[n];` and reject `int a[c];`.
`sizeof a` is not a constant expression, so it can't be used in a case
label or any other context that requires a constant expression. (If
`const int c = n;` made c a constant expression, this would not apply.)
Generated code for constructs that a compiler acccepts is likely to be
identical. For a VLA type with a non-constant length, the compiler must
implicitly store the size somehow. For a VLA type with a length that
the compiler can evaluate at compile time, the compiler is likely to
generate code equivalent to that for a non-VLA.
All positive changes from "not working" to "working", from "working in
runtime" to "working at compile time."
David Brown
2024-10-20 10:55:19 UTC
Permalink
Post by Keith Thompson
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
I think constexpr keyword is unnecessary.
Sure, most language features are strictly unnecessary.
Post by Thiago Adams
Anything you do with it could/should be done with const.
No, absolutely not.
If not, do you have a sample where, using "const" as "constexpr",
would create problems?
The sample I know is VLA.
const int c = 2;
int a[c]; //a is VLA because c is not a constant expression.
But this is not enough to convince me because it is better not to be
a VLA here.
What practical difference would it make? Can you think of any
difference between local variables "a" and "b" defined like this?
enum { n = 2 };
const int c = n;
int a[c];
int b[n];
Can you show any situation where you could use "a" and not "b", or
vice versa, or where the meaning would be different? Can you show any
compiler that treats them differently in code generation (assuming a
compiler that supports enough of C99 to allow it)?
I know of no differences there. That is enough to convince me that it
doesn't matter in the slightest whether it is technically a VLA or
not.
VLAs are optional in C11 and later. A conforming implementation that
doesn't support VLAs will accept `int b[n];` and reject `int a[c];`.
Yes. That's why I said "a compiler that supports enough of C99 to allow
it". (I think it was a really bad idea to make VLAs optional in C11 - I
can't see any justification for it other than pressure from a big
compiler vendor that has long neglected implementation of C standards.)
Post by Keith Thompson
`sizeof a` is not a constant expression, so it can't be used in a case
label or any other context that requires a constant expression. (If
`const int c = n;` made c a constant expression, this would not apply.)
Ah, there you have a difference. Thanks.
Post by Keith Thompson
Generated code for constructs that a compiler acccepts is likely to be
identical. For a VLA type with a non-constant length, the compiler must
implicitly store the size somehow. For a VLA type with a length that
the compiler can evaluate at compile time, the compiler is likely to
generate code equivalent to that for a non-VLA.
Yes, that's the point - and that's why I wonder why Thiago is happy with
an array with a constant expression size, but dislikes one with a
non-constant size that is known and fixed at compile time, just because
it is technically a VLA.
Loading...