On Sat, 10 May 2025 06:43:38 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 04 May 2025 07:31:11 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
[...]
Also having just one form of loop with pre-condition strikes me as
more elegant. Since elegance is strongly subjective, I have no
logical arguments in support of me feelings.
In a recent posting I gave some statistics about the three different
kinds of looping controls (while,for,do/while). do/while loops were
almost 20% of all loops, and more than a quarter of the two kinds of
loops other than for(). Besides being a more pragmatic choice, I
think having the three kinds of loops be distinct in the language is
a better choice, because how we think of the different kinds of loop
is different, and it's helpful to have those differences be readily
apparent in the program, rather than needing to reconstruct them by
looking at code around the loop control fragment.
That sounds like misunderstanding.
I didn't suggest one loop construct. I suggested two constructs: for()
for loops with pre-condition and do-while for loops with post-condition.
On Sat, 10 May 2025 14:29:50 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:
Muttley@dastardlyhq.com writes:
On Sat, 10 May 2025 06:43:38 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:
never necessary). Also it isn't easy to think of a good substitute
word that might be given for this use of 'static', so maybe the
Isn't it?
Where "static" means local to a module the words
"local","module","limit" spring to mind which are far closer to
the intended meaning. Reusing "static" seems somewhat perverse
IMO.
The use I'm talking about here may be illustrated as follows:
double
average( double values[ static 10 ] ){
double total = 0;
for( int i = 0; i < 10; i++ ){
total += values[i];
}
return total / 10;
}
What word would you suggest to be used in place of 'static'
there?
If I knew what the hell it was supposed to do I'd tell you.
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
[...]
It's main potential usefulness is not in the definition of the
function, but in calls to the function. If the calls occur in
a different translation unit from the definition, the compiler
does not have the needed information.
It does if the visible declaration has the same information.
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
[...]
It's main potential usefulness is not in the definition of the
function, but in calls to the function. If the calls occur in
a different translation unit from the definition, the compiler
does not have the needed information.
It does if the visible declaration has the same information.
Like 'restrict', parameter array length information, specified by
way of 'static', is ignored outside of function definitions. As
was intended (with 'restrict' also).
Furthermore, and also like 'restrict', there is no general
way to verify at compile time that the stipulated condition
holds.
Considering the above, it's better to observe the status quo, and
leave any diagnostics up to the discretion of the implementation,
rather than try to retrofit an incompatible change that would
make an infringement be a constraint violation that can't be
checked anyway.
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
[...]
It's main potential usefulness is not in the definition of the
function, but in calls to the function. If the calls occur in
a different translation unit from the definition, the compiler
does not have the needed information.
It does if the visible declaration has the same information.
Like 'restrict', parameter array length information, specified by
way of 'static', is ignored outside of function definitions. As
was intended (with 'restrict' also).
Furthermore, and also like 'restrict', there is no general
way to verify at compile time that the stipulated condition
holds.
Considering the above, it's better to observe the status quo, andI was not suggesting any change to the status quo, only explaining why
leave any diagnostics up to the discretion of the implementation,
rather than try to retrofit an incompatible change that would
make an infringement be a constraint violation that can't be
checked anyway.
On Tue, 06 May 2025 05:59:20 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Wed, 16 Apr 2025 14:09:44 GMT
scott@slp53.sl.home (Scott Lurndal) wrote:
bart <bc@freeuk.com> writes:
On 15/04/2025 20:07, Scott Lurndal wrote:
Let's look at that C again:
for (int i = 1; i < 11; i += 1) # 15 tokens; C
for(i = 1; i++ <= 10;)
I'd reject this code during review.
Hopefully, you too.
I'm curious to know the basis for your reaction. What about the
code would prompt your judgment to reject it? Is it just a
specific reaction, or does it represent some more general pattern
(and if so then what more general pattern)?
First and foremost it was tongue-in-cheek reaction to the article
that Scott posted 2-3 minutes after the article that I was
reacting to.
At the next level, it is true that if I do detailed code review
(which I almost never do) I would indeed reject this code. The
first and sufficient reason is that the code looks superficially
similar to very common idiom, but significantly differs in
behavior. An additional reason is that post-increment operator is
generally harder to reason about than almost any other C operator,
esp. so when used as part of comparison, so, IMHO, readable code
should limit use of post-increment to very common idioms (or
altogether avoid it). The third reason, related to the first two
is that behavior of this loop is way too surprising.
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
[...]
It's main potential usefulness is not in the definition of the
function, but in calls to the function. If the calls occur in
a different translation unit from the definition, the compiler
does not have the needed information.
It does if the visible declaration has the same information.
Like 'restrict', parameter array length information, specified by
way of 'static', is ignored outside of function definitions. As
was intended (with 'restrict' also).
I think that by "is ignored", you mean that compilers are not
required to pay attention to it. [...]
Furthermore, and also like 'restrict', there is no general
way to verify at compile time that the stipulated condition
holds.
Right, but that doesn't prevent implementations from issuing
useful warnings when it can determine that the stipulated
condition does not hold.
Considering the above, it's better to observe the status quo, and
leave any diagnostics up to the discretion of the implementation,
rather than try to retrofit an incompatible change that would
make an infringement be a constraint violation that can't be
checked anyway.
Observing the status quo is better than what, exactly?
The status quo is that the "[static N]" syntax has been in the
language since C99, and programmers and implementations are free
to take advantage of it. I don't recall anyone in this thread
proposing a change to that.
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
[...]
It's main potential usefulness is not in the definition of the
function, but in calls to the function. If the calls occur in
a different translation unit from the definition, the compiler
does not have the needed information.
It does if the visible declaration has the same information.
Like 'restrict', parameter array length information, specified by
way of 'static', is ignored outside of function definitions. As
was intended (with 'restrict' also).
? What "static" does when applied to an array parameter's length is to
render the behavior undefined if the function is called with a pointer
that points to an array that is shorter than the specified length. Are
you saying that it has no such effect except for inside the function definition? I'm not sure what that would even mean - is the behavior undefined only for recursive calls to the function?
Furthermore, and also like 'restrict', there is no general
way to verify at compile time that the stipulated condition
holds.
As I already mentioned, if such verification could have been
generally possible, it should have been a constraint violation.
Because it is not possible in general, but only in certain cases,
making the behavior undefined is the best that can be done. Doing
so encourages implementations to generate a diagnostic when those
cases do come up.
Considering the above, it's better to observe the status quo, and
leave any diagnostics up to the discretion of the implementation,
rather than try to retrofit an incompatible change that would
make an infringement be a constraint violation that can't be
checked anyway.
I was not suggesting any change to the status quo, [...]
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
[...]
It's main potential usefulness is not in the definition of the
function, but in calls to the function. If the calls occur in
a different translation unit from the definition, the compiler
does not have the needed information.
It does if the visible declaration has the same information.
Like 'restrict', parameter array length information, specified by
way of 'static', is ignored outside of function definitions. As
was intended (with 'restrict' also).
I think that by "is ignored", you mean that compilers are not
required to pay attention to it. [...]
I mean it has no effect on program semantics.
Furthermore, and also like 'restrict', there is no general
way to verify at compile time that the stipulated condition
holds.
Right, but that doesn't prevent implementations from issuing
useful warnings when it can determine that the stipulated
condition does not hold.
True, but in many cases they can't, because that information
is not part of the function's type and so often it is not
present.
Considering the above, it's better to observe the status quo, and
leave any diagnostics up to the discretion of the implementation,
rather than try to retrofit an incompatible change that would
make an infringement be a constraint violation that can't be
checked anyway.
Observing the status quo is better than what, exactly?
Better than than trying to retrofit an incompatible change that
would make an infringement be a constraint violation that can't
be checked anyway.
The status quo is that the "[static N]" syntax has been in the
language since C99, and programmers and implementations are free
to take advantage of it. I don't recall anyone in this thread
proposing a change to that.
Neither do I, nor did I mean to imply that anyone had.
It isn't just that checking the condition cannot be done in general.[...]
To be reliable the parameter length information would need to be
part of the function's type. That has implications for type
compatibility and also for the types of pointers-to-function. And
it would mean that removing a 'static' array length specification on
a function definition would necessitate also changing the functions declarations, plus any affected pointers-to-function. Not worth it,
even if in theory it were doable.
Muttley@dastardlyhq.com writes:
On Sat, 10 May 2025 14:29:50 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:
Muttley@dastardlyhq.com writes:
On Sat, 10 May 2025 06:43:38 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:
never necessary). Also it isn't easy to think of a good substitute
word that might be given for this use of 'static', so maybe the
Isn't it?
Where "static" means local to a module the words
"local","module","limit" spring to mind which are far closer to
the intended meaning. Reusing "static" seems somewhat perverse
IMO.
The use I'm talking about here may be illustrated as follows:
double
average( double values[ static 10 ] ){
double total = 0;
for( int i = 0; i < 10; i++ ){
total += values[i];
}
return total / 10;
}
What word would you suggest to be used in place of 'static'
there?
If I knew what the hell it was supposed to do I'd tell you.
When you find out please post your suggested replacement.
Michael S <already5chosen@yahoo.com> writes:
On Sat, 10 May 2025 06:43:38 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 04 May 2025 07:31:11 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
[...]
Also having just one form of loop with pre-condition strikes me as
more elegant. Since elegance is strongly subjective, I have no
logical arguments in support of me feelings.
In a recent posting I gave some statistics about the three
different kinds of looping controls (while,for,do/while).
do/while loops were almost 20% of all loops, and more than a
quarter of the two kinds of loops other than for(). Besides being
a more pragmatic choice, I think having the three kinds of loops
be distinct in the language is a better choice, because how we
think of the different kinds of loop is different, and it's
helpful to have those differences be readily apparent in the
program, rather than needing to reconstruct them by looking at
code around the loop control fragment.
That sounds like misunderstanding.
I didn't suggest one loop construct. I suggested two constructs:
for() for loops with pre-condition and do-while for loops with post-condition.
Yes, I did misunderstand you. The alternative meaning didn't occur
to me. I see it now.
The same posting I mentioned in the previous response gave while()
loops as occurring more than for() and do/while() combined. I
conceptualize for() loops quite differently than while() loops, and
vice versa. By analogy to the only-two-kinds-of-loops suggestion,
the language could forego switch() and provide only if()/else.
To
me, neither of those what-might-be-called-simplifications seems like
a good trade. Have you asked other people to see what their
reactions are?
Incidentally, a language change to C was once proposed, so that
a do/while could also have an expression after the while().
Note that this change is backwards compatible with C as it is,
because a simple semicolon after while() is an empty statement.
Adopting this proposal would mean that the language would allow,
for example
do {
// this part will always be done at least once
// and once more for each time 'condition' is true
} while( condition ){
// this part will be done zero or more times
}
allowing a convenient way of writing "loop-and-a-half" type
loops. Do you have any reaction to this idea? Suppose
the just plain while() style were eliminated, so ordinary
while() loops would instead be written as
do ; while( condition ){
// body of while loop
}
Is that better or worse than having a separate while() statement?
On Sun, 11 May 2025 17:59:31 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wibbled:
Muttley@dastardlyhq.com writes:
If I knew what the hell it was supposed to do I'd tell you.
When you find out please post your suggested replacement.
average( double values[ pointless_keyword 10 ] ){
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
[...]
It's main potential usefulness is not in the definition of the
function, but in calls to the function. If the calls occur in
a different translation unit from the definition, the compiler
does not have the needed information.
It does if the visible declaration has the same information.
Like 'restrict', parameter array length information, specified by
way of 'static', is ignored outside of function definitions. As
was intended (with 'restrict' also).
I think that by "is ignored", you mean that compilers are not
required to pay attention to it. [...]
I mean it has no effect on program semantics.
It affects whether a program has defined or undefined behavior.
(Yes, a conforming compiler could ignore it.)
Furthermore, and also like 'restrict', there is no general
way to verify at compile time that the stipulated condition
holds.
Right, but that doesn't prevent implementations from issuing
useful warnings when it can determine that the stipulated
condition does not hold.
True, but in many cases they can't, because that information
is not part of the function's type and so often it is not
present.
Why would it not be present?
If you mean that someone might use `[static N]` in a function's
definition but not in a declaration, sure, but I would always
make sure they match as closely as possible. [...]
Considering the above, it's better to observe the status quo, and
leave any diagnostics up to the discretion of the implementation,
rather than try to retrofit an incompatible change that would
make an infringement be a constraint violation that can't be
checked anyway.
Observing the status quo is better than what, exactly?
Better than than trying to retrofit an incompatible change that
would make an infringement be a constraint violation that can't
be checked anyway.
And as you seem to have agreed, nobody suggested that. Were we
supposed to guess what it's better than? Or did I miss something?
It strikes me that you have a rather self-centered view of the
world.
The vast majority of all C code is written by people other
than yourself.
On 5/11/25 06:02, David Brown wrote:
On 11/05/2025 10:21, Muttley@dastardlyhq.com wrote:...
On Sat, 10 May 2025 14:29:50 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> gabbled:
The use I'm talking about here may be illustrated as follows:
double
average( double values[ static 10 ] ){
double total = 0;
for( int i = 0; i < 10; i++ ){
total += values[i];
}
return total / 10;
}
What word would you suggest to be used in place of 'static'
there?
If I knew what the hell it was supposed to do I'd tell you.
Using "static" inside array parameters is, IME, extremely rare. It was
added in C99, and tells the compiler that whenever "average" is called,
the "values" parameter points to an array of at least 10 doubles. It
More precisely, it makes it undefined behavior for values to point to an array of less than 10 doubles.
does not affect the signature of the function or compatibility with any
other declarations, and is AFAIK rarely checked by compilers.
I'd have preferred it if violating that requirement was a constraint violation, but it can't be, because there are many cases where a
compiler cannot be sure how long the array is that a pointer points at.
However, the fact that the behavior is undefined justifies a compiler reacting to the case when it can be sure that the requirement will be violated.
That's the main reason I like this feature, and dislike
compilers that fail to take advantage of that opportunity. I never
considered it to be about efficiency, though there are cases where it
can result in more efficient code.
In an example like the one above, it is completely useless for
compilation - it tells the compiler nothing that it does not already
know. An optimising compiler will see that you are accessing values[0]
to values[9], and if it can get better results through vectorising,
prefetching, etc., then it will do so. (You can argue that the "static
10" is still useful as an indicator to human readers, but I am not
convinced of that.)
It's main potential usefulness is not in the definition of the function,
but in calls to the function. If the calls occur in a different
translation unit from the definition, the compiler does not have the
needed information.
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
[...]
It isn't just that checking the condition cannot be done in general.[...]
To be reliable the parameter length information would need to be
part of the function's type. That has implications for type
compatibility and also for the types of pointers-to-function. And
it would mean that removing a 'static' array length specification on
a function definition would necessitate also changing the functions
declarations, plus any affected pointers-to-function. Not worth it,
even if in theory it were doable.
In my opinion, keeping a function's definition and declarations
consistent is absolutely worth it, even if the language might not
require it.
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
[...]
It's main potential usefulness is not in the definition of the
function, but in calls to the function. If the calls occur in
a different translation unit from the definition, the compiler
does not have the needed information.
It does if the visible declaration has the same information.
Like 'restrict', parameter array length information, specified by
way of 'static', is ignored outside of function definitions. As
was intended (with 'restrict' also).
I think that by "is ignored", you mean that compilers are not
required to pay attention to it. [...]
I mean it has no effect on program semantics.
It affects whether a program has defined or undefined behavior.
(Yes, a conforming compiler could ignore it.)
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:[...]
[...]If you mean that someone might use `[static N]` in a function's
definition but not in a declaration, sure, but I would always
make sure they match as closely as possible. [...]
It strikes me that you have a rather self-centered view of the
world. The vast majority of all C code is written by people other
than yourself.
I am not convinced that it is actually useful as an error checking[...]
mechanism in many situations. In a lot of code, you simply don't have
a compile-time checkable array sizes - you have a pointer, and a
run-time variable for the size. When you are calling your function
with a "static" array size, the compiler does not have any way to
check your pointer for correctness.
It isn't just that checking the condition cannot be done in general.
To be reliable the parameter length information would need to be
part of the function's type.
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
[...]
It's main potential usefulness is not in the definition of the
function, but in calls to the function. If the calls occur in
a different translation unit from the definition, the compiler
does not have the needed information.
It does if the visible declaration has the same information.
Like 'restrict', parameter array length information, specified by
way of 'static', is ignored outside of function definitions. As
was intended (with 'restrict' also).
? What "static" does when applied to an array parameter's length is to
render the behavior undefined if the function is called with a pointer
that points to an array that is shorter than the specified length. Are
you saying that it has no such effect except for inside the function
definition? I'm not sure what that would even mean - is the behavior
undefined only for recursive calls to the function?
What I mean is that such uses of 'static' have no effect when
used in declarations that are not part of a definition.
On 12/05/2025 15:19, Tim Rentsch wrote:
It strikes me that you have a rather self-centered view of the
world.
So do you. So do I. So does everybody else. Your eyes are at the
precise centre of your observable universe.
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
[...]
It isn't just that checking the condition cannot be done in general.
To be reliable the parameter length information would need to be
part of the function's type.
The problem is much deeper than that. The same pointer can point
to different arrays, or different positions in the same array,
during different passes through the same line of code. Some of
those would violate this rule, others would not. I don't see how
violating such a rule could ever be made a constraint violation.
[...]
Richard Heathfield <rjh@cpax.org.uk> writes:
On 12/05/2025 15:19, Tim Rentsch wrote:
It strikes me that you have a rather self-centered view of the
world.
So do you. So do I. So does everybody else. Your eyes are at the
precise centre of your observable universe.
I think you have misunderstood me.
(At some later time I may have more to say about your other
comments, but it seemed important to respond to this part
more promptly.)
David Brown <david.brown@hesbynett.no> writes:
[...]
I am not convinced that it is actually useful as an error checking[...]
mechanism in many situations. In a lot of code, you simply don't have
a compile-time checkable array sizes - you have a pointer, and a
run-time variable for the size. When you are calling your function
with a "static" array size, the compiler does not have any way to
check your pointer for correctness.
Using [static N] in an array parameter declaration also requires the
caller to pass a non-NULL pointer. If I want to tell the compiler
that an argument must not be a NULL pointer, I can write:
void func(int arg[static 1]);
func(NULL) then has undefined behavior, and a compiler is likely
to warn about it. (Of course some UB will be missed if the compiler
can't detect it.)
[...]
Incidentally, a language change to C was once proposed, so that
a do/while could also have an expression after the while().
Note that this change is backwards compatible with C as it is,
because a simple semicolon after while() is an empty statement.
Adopting this proposal would mean that the language would allow,
for example
do {
// this part will always be done at least once
// and once more for each time 'condition' is true
} while( condition ){
// this part will be done zero or more times
}
allowing a convenient way of writing "loop-and-a-half" type
loops. [...]
On 12/05/2025 15:19, Tim Rentsch wrote:
It strikes me that you have a rather self-centered view of the
world.
So do you. So do I. So does everybody else. Your eyes are at the
precise centre of your observable universe.
The vast majority of all C code is written by people other
than yourself.
And the vast majority of those people are entitled to express their
opinion, just as you are entitled to express yours and Keith is
entitled to express his.
I hope I'm wrong, but it strikes me that you're trying to pick a fight
with Keith. No doubt you have your reasons, but I would have expected
better from a man of your calibre.
On 12/05/2025 15:19, Tim Rentsch wrote:
[...]
[...]
I hope I'm wrong, but it strikes me that you're trying to pick a fight
with Keith. No doubt you have your reasons, but I would have expected
better from a man of your calibre.
Hey! You do you. What would I know? And it really is none of my
business, which is precisely why, back in the day, grown-ups who wanted
to lock horns would take it to email.
On 11/05/2025 23:43, James Kuyper wrote:[...]
More precisely, it makes it undefined behavior for values to point to an
array of less than 10 doubles.
The wording of the C standard (C11, as that's what I have open at the
moment) is :
"""
If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element
of an array with at least as many elements as specified by the size expression.
"""
[...]
On 12.05.2025 17:08, David Brown wrote:
On 11/05/2025 23:43, James Kuyper wrote:[...]
More precisely, it makes it undefined behavior for values to point to an >>> array of less than 10 doubles.
The wording of the C standard (C11, as that's what I have open at the
moment) is :
"""
If the keyword static also appears within the [ and ] of the array type
derivation, then for each call to the function, the value of the
corresponding actual argument shall provide access to the first element
of an array with at least as many elements as specified by the size
expression.
"""
Oh! - This is somewhat surprising to me. - When I first read about
the "arr[static N]" I assumed that it would be possible to pass any sub-array, say "&arr[8]" (or "arr+8") as long as it's large enough
to still have N elements from the starting point, but the quote says explicitly "access to the _first_ element of an array" (which I'd
interpret as "&arr[0]" (or "arr"). - Unless I misinterpreted that;
what would be the reason for that?
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
On 12.05.2025 17:08, David Brown wrote:
On 11/05/2025 23:43, James Kuyper wrote:
[...]
More precisely, it makes it undefined behavior for values to point to an >>>> array of less than 10 doubles.
The wording of the C standard (C11, as that's what I have open at the
moment) is :
"""
If the keyword static also appears within the [ and ] of the array type
derivation, then for each call to the function, the value of the
corresponding actual argument shall provide access to the first element
of an array with at least as many elements as specified by the size
expression.
"""
Oh! - This is somewhat surprising to me. - When I first read about
the "arr[static N]" I assumed that it would be possible to pass any
sub-array, say "&arr[8]" (or "arr+8") as long as it's large enough
to still have N elements from the starting point, but the quote says
explicitly "access to the _first_ element of an array" (which I'd
interpret as "&arr[0]" (or "arr"). - Unless I misinterpreted that;
what would be the reason for that?
My personal interpretation is that this:
void func(int arr[static 5]) {
}
int main(void) {
int arr[10];
func(arr+5); // OK
// func(arr+6); // UB
}
is valid, because, for example, the last 5 elements of a 10-element
array object can be treated as a 5-element array object. gcc seems
to agree, based on the fact that it warns about func(arr+6) but
not about func(arr+5).
This is a fundamental part of my mental model of C, but in a few
minutes of searching I wasn't able to find explicit wording in the
standard that supports it.
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:[...]
My personal interpretation is that this:
void func(int arr[static 5]) {
}
int main(void) {
int arr[10];
func(arr+5); // OK
// func(arr+6); // UB
}
is valid, because, for example, the last 5 elements of a 10-element
array object can be treated as a 5-element array object. gcc seems
to agree, based on the fact that it warns about func(arr+6) but
not about func(arr+5).
This is a fundamental part of my mental model of C, but in a few
minutes of searching I wasn't able to find explicit wording in the
standard that supports it.
In N1570, 6.7.6.3 p7.
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
[...]
My personal interpretation is that this:
void func(int arr[static 5]) {
}
int main(void) {
int arr[10];
func(arr+5); // OK
// func(arr+6); // UB
}
is valid, because, for example, the last 5 elements of a 10-element
array object can be treated as a 5-element array object. gcc seems
to agree, based on the fact that it warns about func(arr+6) but
not about func(arr+5).
This is a fundamental part of my mental model of C, but in a few
minutes of searching I wasn't able to find explicit wording in the
standard that supports it.
In N1570, 6.7.6.3 p7.
Did you mean to imply that that paragraph supports (or refutes) my
statement? [...]
"""
A declaration of a parameter as ??array of _type_?? shall
be adjusted to ??qualified pointer to _type_??, where the
type qualifiers (if any) are those specified within the [ and ]
of the array type derivation. If the keyword static also appears
within the [ and ] of the array type derivation, then for each call
to the function, the value of the corresponding actual argument
shall provide access to the first element of an array with at least
as many elements as specified by the size expression.
"""
The question is whether, for example, the last 5 elements of a
10-element array object can be treated as a 5-element array object.
If someone can cite wording in the standard that answers that
question, I'd appreciate it. (I'll be happier if the answer is yes.)
Looking into this a bit more, I realize that the question doesn't
matter if there's no "static" keyword between the [ and ]. In that
case, the parameter is of pointer type, and the description of
pointer arithmetic (N1570 6.5.6p8) explicitly allows the pointer
to point to the i-th element of an array object. The wording for
[static N] is the only place I've seen (so far) that specifically
refers to the *first* element of an array object, raising the
question of whether a subobject of an array object is itself an
array object.
This might just be some slightly sloppy wording that was
introduced in C99 and never corrected.
For example, given this code:
```
void without_static(int arr[]) {
(void)arr[4];
}
void with_static(int arr[static 5]) {
(void)arr[4];
}
int main(void) {
int arr[10] = { 0 };
without_static(arr+5);
with_static(arr+5);
}
```
there's no problem with the call `without_static(arr+5)`, but the
call `with_static(arr+5)` has defined behavior if and only if the
last 5 elements of a 10-element array object can be treated as a
5-element array object.
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:[...]
My personal interpretation is that this:
void func(int arr[static 5]) {
}
int main(void) {
int arr[10];
func(arr+5); // OK
// func(arr+6); // UB
}
is valid, because, for example, the last 5 elements of a 10-element
array object can be treated as a 5-element array object. gcc seems
to agree, based on the fact that it warns about func(arr+6) but
not about func(arr+5).
This is a fundamental part of my mental model of C, but in a few
minutes of searching I wasn't able to find explicit wording in the
standard that supports it.
In N1570, 6.7.6.3 p7.
Did you mean to imply that that paragraph supports (or refutes) my
statement? [...]
No. I posted the reference to say that the cited paragraph supports
the conclusion that 'func(arr+6)' is undefined behavior.
"""
A declaration of a parameter as ??array of _type_?? shall
be adjusted to ??qualified pointer to _type_??, where the
type qualifiers (if any) are those specified within the [ and ]
of the array type derivation. If the keyword static also appears
within the [ and ] of the array type derivation, then for each call
to the function, the value of the corresponding actual argument
shall provide access to the first element of an array with at least
as many elements as specified by the size expression.
"""
The question is whether, for example, the last 5 elements of a
10-element array object can be treated as a 5-element array object.
If someone can cite wording in the standard that answers that
question, I'd appreciate it. (I'll be happier if the answer is yes.)
To me it seems obvious that 6.7.6.3 p7 is meant to cover the
case of 'func(arr+6)' as being undefined behavior.
Note that 6.7.6.3 p7 doesn't say "array object", it says just
"array". I believe the choice of wording is neither an accident nor
an oversight.
Looking into this a bit more, I realize that the question doesn't
matter if there's no "static" keyword between the [ and ]. In that
case, the parameter is of pointer type, and the description of
pointer arithmetic (N1570 6.5.6p8) explicitly allows the pointer
to point to the i-th element of an array object. The wording for
[static N] is the only place I've seen (so far) that specifically
refers to the *first* element of an array object, raising the
question of whether a subobject of an array object is itself an
array object.
Again, not an array object, just an array.
This might just be some slightly sloppy wording that was
introduced in C99 and never corrected.
I draw the opposite conclusion. The wording of 6.7.6.3 p7 was
carefully chosen so that it would cover cases like 'func(arr+6)'.
is valid, because, for example, the last 5 elements of a 10-element
array object can be treated as a 5-element array object. gcc seems
to agree, based on the fact that it warns about func(arr+6) but
not about func(arr+5).
This is a fundamental part of my mental model of C, but in a few
minutes of searching I wasn't able to find explicit wording in the
standard that supports it.
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:....
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:[...]
My personal interpretation is that this:
void func(int arr[static 5]) {
}
int main(void) {
int arr[10];
func(arr+5); // OK
// func(arr+6); // UB
}
is valid, because, for example, the last 5 elements of a 10-element
array object can be treated as a 5-element array object. gcc seems
to agree, based on the fact that it warns about func(arr+6) but
not about func(arr+5).
This is a fundamental part of my mental model of C, but in a few
minutes of searching I wasn't able to find explicit wording in the
standard that supports it.
In N1570, 6.7.6.3 p7.
Did you mean to imply that that paragraph supports (or refutes) my
statement? [...]
No. I posted the reference to say that the cited paragraph supports
the conclusion that 'func(arr+6)' is undefined behavior.
To me it seems obvious that 6.7.6.3 p7 is meant to cover the
case of 'func(arr+6)' as being undefined behavior.
But that's not the question I was addressing. My question is whether func(arr+5) has defined behavior, based on whether or not a+5 points to
the *first element* of an array.
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
[...]
My personal interpretation is that this:
void func(int arr[static 5]) {
}
int main(void) {
int arr[10];
func(arr+5); // OK
// func(arr+6); // UB
}
is valid, because, for example, the last 5 elements of a 10-element
array object can be treated as a 5-element array object. gcc seems
to agree, based on the fact that it warns about func(arr+6) but
not about func(arr+5).
This is a fundamental part of my mental model of C, but in a few
minutes of searching I wasn't able to find explicit wording in the
standard that supports it.
In N1570, 6.7.6.3 p7.
Did you mean to imply that that paragraph supports (or refutes) my
statement? [...]
No. I posted the reference to say that the cited paragraph supports
the conclusion that 'func(arr+6)' is undefined behavior.
I wish you had said so in the first place. Of course func(arr+6) has undefined behavior. Did anyone in this thread say or imply otherwise?
"""
A declaration of a parameter as ??array of _type_?? shall
be adjusted to ??qualified pointer to _type_??, where the
type qualifiers (if any) are those specified within the [ and ]
of the array type derivation. If the keyword static also appears
within the [ and ] of the array type derivation, then for each call
to the function, the value of the corresponding actual argument
shall provide access to the first element of an array with at least
as many elements as specified by the size expression.
"""
The question is whether, for example, the last 5 elements of a
10-element array object can be treated as a 5-element array object.
If someone can cite wording in the standard that answers that
question, I'd appreciate it. (I'll be happier if the answer is yes.)
To me it seems obvious that 6.7.6.3 p7 is meant to cover the
case of 'func(arr+6)' as being undefined behavior.
But that's not the question I was addressing. My question is whether func(arr+5) has defined behavior, based on whether or not a+5 points to
the *first element* of an array.
Note that 6.7.6.3 p7 doesn't say "array object", it says just
"array". I believe the choice of wording is neither an accident nor
an oversight.
Then please explain what you see as the difference. Wording in the
standard to support the distinction would be welcome.
Given `int arr[10];`, do the last 5 elements of arr constitute an
"array"? Do they constitute an "array object"? And the same
questions for arr as a whole.
Looking into this a bit more, I realize that the question doesn't
matter if there's no "static" keyword between the [ and ]. In that
case, the parameter is of pointer type, and the description of
pointer arithmetic (N1570 6.5.6p8) explicitly allows the pointer
to point to the i-th element of an array object. The wording for
[static N] is the only place I've seen (so far) that specifically
refers to the *first* element of an array object, raising the
question of whether a subobject of an array object is itself an
array object.
Again, not an array object, just an array.
This might just be some slightly sloppy wording that was
introduced in C99 and never corrected.
I draw the opposite conclusion. The wording of 6.7.6.3 p7 was
carefully chosen so that it would cover cases like 'func(arr+6)'.
But func(arr+5) is the case I was wondering about. (That's why I
commented out the func(arr+6) call.)
On 5/13/25 22:37, Keith Thompson wrote:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
[...]
My personal interpretation is that this:
void func(int arr[static 5]) {
}
int main(void) {
int arr[10];
func(arr+5); // OK
// func(arr+6); // UB
}
is valid, because, for example, the last 5 elements of a 10-element >>>>>> array object can be treated as a 5-element array object. gcc seems >>>>>> to agree, based on the fact that it warns about func(arr+6) but
not about func(arr+5).
This is a fundamental part of my mental model of C, but in a few
minutes of searching I wasn't able to find explicit wording in the >>>>>> standard that supports it.
In N1570, 6.7.6.3 p7.
Did you mean to imply that that paragraph supports (or refutes) my
statement? [...]
No. I posted the reference to say that the cited paragraph supports
the conclusion that 'func(arr+6)' is undefined behavior.
...
To me it seems obvious that 6.7.6.3 p7 is meant to cover the
case of 'func(arr+6)' as being undefined behavior.
But that's not the question I was addressing. My question is whether
func(arr+5) has defined behavior, based on whether or not a+5 points to
the *first element* of an array.
Tim - [...]
Progarms that manipulate strings using standard library functions often
take advantage of the above. Strings are defined as null-terminated
arrays; but it is very common for strings to be arrays that are displaced within larger arrays.
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:[...]
My personal interpretation is that this:
void func(int arr[static 5]) {
}
int main(void) {
int arr[10];
func(arr+5); // OK
// func(arr+6); // UB
}
is valid, because, for example, the last 5 elements of a 10-element >>>>>> array object can be treated as a 5-element array object. gcc seems >>>>>> to agree, based on the fact that it warns about func(arr+6) but
not about func(arr+5).
This is a fundamental part of my mental model of C, but in a few
minutes of searching I wasn't able to find explicit wording in the >>>>>> standard that supports it.
In N1570, 6.7.6.3 p7.
Did you mean to imply that that paragraph supports (or refutes) my
statement? [...]
No. I posted the reference to say that the cited paragraph supports
the conclusion that 'func(arr+6)' is undefined behavior.
I wish you had said so in the first place. Of course func(arr+6) has
undefined behavior. Did anyone in this thread say or imply otherwise?
In my view the same reasoning about the meaning applies to both
cases, so there is no reason to talk about them separately.
"""
A declaration of a parameter as ??array of _type_?? shall
be adjusted to ??qualified pointer to _type_??, where the
type qualifiers (if any) are those specified within the [ and ]
of the array type derivation. If the keyword static also appears
within the [ and ] of the array type derivation, then for each call
to the function, the value of the corresponding actual argument
shall provide access to the first element of an array with at least
as many elements as specified by the size expression.
"""
The question is whether, for example, the last 5 elements of a
10-element array object can be treated as a 5-element array object.
If someone can cite wording in the standard that answers that
question, I'd appreciate it. (I'll be happier if the answer is yes.)
To me it seems obvious that 6.7.6.3 p7 is meant to cover the
case of 'func(arr+6)' as being undefined behavior.
But that's not the question I was addressing. My question is whether
func(arr+5) has defined behavior, based on whether or not a+5 points to
the *first element* of an array.
To me it seems obvious that 6.7.6.3 p7 is meant to cover the
case of 'func(arr+5)' as satisfying the "shall" requirement,
for the same reasons that it is meant to cover the case of
'func(arr+6)' as being undefined behavior.
Note that 6.7.6.3 p7 doesn't say "array object", it says just
"array". I believe the choice of wording is neither an accident nor
an oversight.
Then please explain what you see as the difference. Wording in the
standard to support the distinction would be welcome.
Given `int arr[10];`, do the last 5 elements of arr constitute an
"array"? Do they constitute an "array object"? And the same
questions for arr as a whole.
The meanings follow from a plain understanding of the English
language.
Consider the following example:
typedef struct { int s; float f; } T;
extern void foo( unsigned char blah[ static sizeof(T)-1 ] );
void
bas( T *it ){
foo( (unsigned char *)it + 1 );
}
There is no array object. But surely there is an array (or at
least an array is indicatated, and an array is present if 'it' is
a valid pointer). This example satisfies the "shall" requirement
in 6.7.6.3 p7, despite there being no array object in sight.
Kaz Kylheku <643-408-1753@kylheku.com> writes:
[...]
Progarms that manipulate strings using standard library functions often
take advantage of the above. Strings are defined as null-terminated
arrays; but it is very common for strings to be arrays that are displaced
within larger arrays.
To be pedantic, a string is defined as "a contiguous sequence of
characters terminated by and including the first null character".
The word "array" is not used. It does seem fairly obvious that
the contiguous sequence will be stored in an array (array object?),
but the standard doesn't quite say so.
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
On 12.05.2025 17:08, David Brown wrote:
On 11/05/2025 23:43, James Kuyper wrote:[...]
More precisely, it makes it undefined behavior for values to point to an >>>> array of less than 10 doubles.
The wording of the C standard (C11, as that's what I have open at the
moment) is :
"""
If the keyword static also appears within the [ and ] of the array type
derivation, then for each call to the function, the value of the
corresponding actual argument shall provide access to the first element
of an array with at least as many elements as specified by the size
expression.
"""
Oh! - This is somewhat surprising to me. - When I first read about
the "arr[static N]" I assumed that it would be possible to pass any
sub-array, say "&arr[8]" (or "arr+8") as long as it's large enough
to still have N elements from the starting point, but the quote says
explicitly "access to the _first_ element of an array" (which I'd
interpret as "&arr[0]" (or "arr"). - Unless I misinterpreted that;
what would be the reason for that?
My personal interpretation is that this:
void func(int arr[static 5]) {
}
int main(void) {
int arr[10];
func(arr+5); // OK
// func(arr+6); // UB
}
is valid, because, for example, the last 5 elements of a 10-element
array object can be treated as a 5-element array object. gcc seems
to agree, based on the fact that it warns about func(arr+6) but
not about func(arr+5).
This is a fundamental part of my mental model of C, but in a few
minutes of searching I wasn't able to find explicit wording in the
standard that supports it.
[...]
I believe we can reassure Janis that your example code will be
considered valid by any real-world compiler.
But it would be nice to
find some combination of standard paragraphs that guarantee it.
On Sun, 11 May 2025 17:30:14 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
[suggestion to keep for() and eliminate while()]
[a mention was made of statistics given in another posting
that reported a ratio of while()/for() of roughly 2.3 to 1.]
[upthread there was a different posting, from Richard
Heathfield, that gave statistics reflecting a ratio
of for()/while() of approximately 3 to 1, IIRC]
[...] while() does not help anything relatively to for().
My interpretation matches yours. I can't find any indication in the
standard of a definition of what an "array" actually means
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
[...]
If you mean that someone might use `[static N]` in a function's
definition but not in a declaration, sure, but I would always
make sure they match as closely as possible. [...]
It strikes me that you have a rather self-centered view of the
world. The vast majority of all C code is written by people other
than yourself.
[...]
Tim, I am not interested in exchanging personal insults with you.
(Yes, the quoted text above comes across as in insult, however you
intended it.)
If the only way to avoid that is to filter out your posts, I will,
with some regret, do that. I would miss out on your technical
contributions, but I'm willing to pay that price to avoid your
hostility.
On 13/05/2025 06:42, Tim Rentsch wrote:
Richard Heathfield <rjh@cpax.org.uk> writes:
On 12/05/2025 15:19, Tim Rentsch wrote:
It strikes me that you have a rather self-centered view of the
world.
So do you. So do I. So does everybody else. Your eyes are at the
precise centre of your observable universe.
I think you have misunderstood me.
I hope so, because the alternative is unpalatable.
(At some later time I may have more to say about your other
comments, but it seemed important to respond to this part
more promptly.)
I think you chose the least important part to respond to, so maybe you
have misunderstood me, too.
I was trying to defend an honourable man from what seemed to me to be
an unfair and unnecessarily unkind observation. The paragraph you
quote above acknowledges that in some literal sense your accusation of self-centredness is accurate, and so implies by omission that the more metaphorical sense that I think you intended is /not/ accurate.
A fine distinction, some might say. But that's what the other
paragraphs were for.
There was no animosity meant in my comments. I am very sorry
if it came across otherwise. I am making an effort to frame
my future statements to help with this.
On 5/14/25 07:00, David Brown wrote:
...
My interpretation matches yours. I can't find any indication in the
standard of a definition of what an "array" actually means
This is a problem with all of the derived types (6.2.5p25). There are definitions of the terms "array type", "structure type:, "union type", "function type", and "pointer type", but no definitions of the things
that those types are types of. My interpretation is that for each of
those object types, "X" is short-hand for "an object of X type". I
haven't figured out suitable wording to define what a function is,
since it isn't an object. The best I've come up with is "a thing of
function type".
Kaz Kylheku <643-408-1753@kylheku.com> writes:
[...]
Progarms that manipulate strings using standard library functions
often take advantage of the above. Strings are defined as
null-terminated arrays; but it is very common for strings to be
arrays that are displaced within larger arrays.
To be pedantic, a string is defined as "a contiguous sequence of
characters terminated by and including the first null character".
The word "array" is not used. It does seem fairly obvious that
the contiguous sequence will be stored in an array (array
object?), but the standard doesn't quite say so.
Consider the following program:
#include <stdio.h>
#include <string.h>
typedef unsigned long long ULL;
ULL hello = ((((0ULL +'o' <<8) +'l' <<8) +'l' <<8) +'e' <<8) + 'h';
int
main(){
printf( "length is %zu\n", strlen( (char*)&hello ) );
return 0;
}
On a little endian machine (with CHAR_BIT == 8) this program works,
and TTBOMK conforms to both the letter and the spirit of the C
standard, without any undefined behavior (on that platform). Yet
there are no arrays in sight, and certainly no array objects.
Am 10.06.2025 um 15:01 schrieb Tim Rentsch:
Consider the following program:
#include <stdio.h>
#include <string.h>
typedef unsigned long long ULL;
ULL hello = ((((0ULL +'o' <<8) +'l' <<8) +'l' <<8) +'e' <<8) + 'h';
int
main(){
printf( "length is %zu\n", strlen( (char*)&hello ) );
return 0;
}
On a little endian machine (with CHAR_BIT == 8) this program works,
and TTBOMK conforms to both the letter and the spirit of the C
standard, without any undefined behavior (on that platform). Yet
there are no arrays in sight, and certainly no array objects.
There are not much remaining big-endian architectures today.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 10.06.2025 um 15:01 schrieb Tim Rentsch:
Consider the following program:
#include <stdio.h>
#include <string.h>
typedef unsigned long long ULL;
ULL hello = ((((0ULL +'o' <<8) +'l' <<8) +'l' <<8) +'e' <<8) +
'h';
int
main(){
printf( "length is %zu\n", strlen( (char*)&hello ) );
return 0;
}
On a little endian machine (with CHAR_BIT == 8) this program works,
and TTBOMK conforms to both the letter and the spirit of the C
standard, without any undefined behavior (on that platform). Yet
there are no arrays in sight, and certainly no array objects.
There are not much remaining big-endian architectures today.
Ethernet is big-endian at the byte level and little-endian
at the bit level.
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 10.06.2025 um 15:01 schrieb Tim Rentsch:
Consider the following program:
#include <stdio.h>
#include <string.h>
typedef unsigned long long ULL;
ULL hello = ((((0ULL +'o' <<8) +'l' <<8) +'l' <<8) +'e' <<8) + 'h'; >>>
int
main(){
printf( "length is %zu\n", strlen( (char*)&hello ) );
return 0;
}
On a little endian machine (with CHAR_BIT == 8) this program works,
and TTBOMK conforms to both the letter and the spirit of the C
standard, without any undefined behavior (on that platform). Yet
there are no arrays in sight, and certainly no array objects.
There are not much remaining big-endian architectures today.
Ethernet is big-endian at the byte level and little-endian
at the bit level.
Sysop: | Tetrazocine |
---|---|
Location: | Melbourne, VIC, Australia |
Users: | 8 |
Nodes: | 8 (0 / 8) |
Uptime: | 95:37:29 |
Calls: | 161 |
Files: | 21,502 |
Messages: | 78,438 |