• Re: Loops (was Re: do { quit; } else { })

    From Tim Rentsch@3:633/280.2 to All on Mon May 12 10:30:14 2025
    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?

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Mon May 12 10:59:31 2025
    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.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Mon May 12 11:15:33 2025
    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.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Keith Thompson@3:633/280.2 to All on Mon May 12 12:09:03 2025
    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. But in fact both gcc and clang
    issue (non-required) warnings in some cases where it's appropriate,
    based in information given by "[static N]". "[static 1]" can be
    used to require that the argument must be non-null (with UB if the
    requirement is violated).

    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.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: None to speak of (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Mon May 12 14:07:15 2025
    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, only explaining why
    the status quo is what it is.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Mon May 12 16:48:26 2025
    Michael S <already5chosen@yahoo.com> writes:

    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.

    I took the posting at face value.

    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.

    I see your comments as saying a few different things. My intention
    below is to give fair paraphrases; please voice an objection if you
    feel that this was not done.

    One: the given code syntactically resembles a common code pattern
    but has quite different semantics.

    Two: postfix ++ is harder to understand than other operators.

    Three: the combination of postfix ++ and a comparison operator
    is even harder to understand than its simpler uses.

    Four: postfix ++ should never be used except in familiar and
    commonly used patterns.

    Five: the effect of the for() controlling statement is not what
    most readers (selected from experienced developers) would expect.

    Would you say that these statements above give a fair restatement
    of your comments? Or have I missed or misrepresented something?

    Taking the above points as fair restatements, here are my reactions.

    Point one is never a reason to reject a given code fragment. If a
    piece of code intends to express a particular semantics, but happens
    to resemble a more common pattern that has different semantics, that
    by itself is never reason to reject the code under consideration.
    It's reasonable to say that a comment be given to alert a reader to
    an unobvious difference, but not to reject the code outright.

    Point two is true at least insofar as postfix ++ is more complicated
    than simple arithmetic operators like + and *. The same could be
    said of all operators with side-effects. Do you think postfix ++ is
    more complicated than postfix --? Both postfix ++ and postfix --
    appear in common and familiar patterns. I don't think the given
    code fragment should be rejected solely for using a postfix ++.

    Point three is certainly true, at least in comparison with using
    postfix ++ by itself. But I don't see why you think using the
    result with a comparison operator is more complicated than other
    compound uses. Consider these code fragments, not too difficult
    I think for most developers:

    *lines++ = next_input_line();
    while( i-- > 0 ) ...

    I don't see either of these examples as being too different than the
    condition 'i++ <= 10'. Is your only reason for rejecting the given
    code is that you find it unfamiliar?

    Point four seems to say explicitly what came up implicitly in point
    three. I think a lot of people follow a similar rule, one not
    necessarily restricted to postfix ++ or other less-used patterns.
    As a guideline I think that's okay; as an inviolate rule I think
    it's wrong. Developers should always write code in a way that they
    feel best expresses their intentions, whether that way is an old
    way or a new way. A second consideration is that, if code is only
    ever written in old familiar ways, then newer and better ways will
    never be discovered. Taking a conservative stance is fine most of
    the time; always vetoing a new form just because it is new is
    overdoing it.

    Point five seems like simply another way of saying, in a more
    generic way, the view raised in point four, or maybe points four
    and one in combination. Same response as was given above.

    I might summarize my reactions as follows. I am philosophically
    opposed to the idea that code should only ever be written in common
    forms or that it should be "dumbed down" for less sophisticated
    developers. An advantage of C is that it is small enough so any
    experienced developer can understand all of it. If someone isn't
    capable of handling basic expressions like those under discussion
    here then they just shouldn't be programming.

    Incidentally, I might agree with you in the sense that I think
    the semantics for the code being considered can be effected using
    code that is either more familiar, or easier to follow than how
    it was written above, or both. If that is your actual underlying
    objection then I think we are pretty much on the same page. My
    response above though gives reactions to what was written, not
    what I imagined you were thinking.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Mon May 12 17:16:34 2025
    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.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Mon May 12 17:43:22 2025
    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.

    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.

    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.

    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, [...]

    I didn't mean to imply you had.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Keith Thompson@3:633/280.2 to All on Mon May 12 19:23:59 2025
    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. And gcc and clang
    (and possibly other compilers) will issue meaningful warnings on
    the basis of `[static N]` in a function declaration, even if that
    declaration is not part of a definition.

    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?

    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.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: None to speak of (3:633/280.2@fidonet)
  • From Keith Thompson@3:633/280.2 to All on Mon May 12 19:27:28 2025
    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.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: None to speak of (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Mon May 12 20:11:43 2025
    On Sun, 11 May 2025 17:59:31 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wibbled:
    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.

    average( double values[ pointless_keyword 10 ] ){


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Michael S@3:633/280.2 to All on Mon May 12 23:18:19 2025
    On Sun, 11 May 2025 17:30:14 -0700
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    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.

    I don't see it as the same or similar. if we compare switch() with if/ if-else/else chain it's clear that switch() helps DRY which is very
    important (most important?) principle of programming.
    OTOH, while() does not help anything relatively to for().

    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
    }


    That is an interesting idea.
    Loops like those do happen quite often in my practice. Of course, if
    have to code them as
    for (;;) {
    ...
    if (!condition)
    break;
    ...
    }

    I find it probable that proposed extended do-while is somewhat easier
    for reader, if for nothing else then because positive logical
    conditions tend to be easier to grasp then negative conditions.

    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?

    I don't think that it's the same. for(;cond;) alternative is less
    clumsy and is not even longer than while(cond) in # of characters.

    If we compare to newer languages, authors of Go went one step further
    and completely gave up on loop with post-condition. Probably for early
    70s that was too radical. May be, it is still too radical now. I didn't
    write a lot of Go, so can't tell.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Michael S@3:633/280.2 to All on Tue May 13 00:09:07 2025
    On Mon, 12 May 2025 10:11:43 -0000 (UTC)
    Muttley@DastardlyHQ.org wrote:

    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 ] ){


    Richard Heathfield recently proposed newfangled_gibberish :-)



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Tue May 13 00:19:00 2025
    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:

    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.)

    Please read again what I said: parameter array length information,
    specified by way of 'static', is ignored _outside of function
    definitions_.

    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. [...]

    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.

    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?

    There was no reason to guess, because it was written in plain
    English in the earlier posting.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Richard Heathfield@3:633/280.2 to All on Tue May 13 00:34:51 2025
    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.

    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.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: Fix this later (3:633/280.2@fidonet)
  • From David Brown@3:633/280.2 to All on Tue May 13 01:08:32 2025
    On 11/05/2025 23:43, James Kuyper wrote:
    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.


    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.
    """

    I think my wording is at least as "precise" as yours. The potential UB
    here comes from violating the "shall" requirement.


    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.

    Indeed. I am also a big fan, in general, of making mistakes in code
    into compiler errors when possible - I'd rather the compiler found my
    bugs than leave it to run-time testing!

    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.

    Unfortunately, that is not quite true. A C programmer is free to write whatever nonsense and run-time UB they like, as long as that UB is not actually "executed". So a compiler, if it aims to be conforming and to
    accept code with well-defined behaviour, has to be sure that the bad
    code in question would inevitably be executed before it is justified in rejecting the code with an error.

    (When the user has asked for non-conforming behaviour, or additional
    analysis and warnings, then of course the compiler can complain when it
    sees a potential error. Such warnings are almost always a good idea.)

    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.


    The C99 rational says it was added for efficiency reasons. But often efficiency and static error analysis go together - the more information
    the compiler has, the better it is at both tasks. And I agree with your attitude of emphasising the static error analysis as being more
    important than the efficiency considerations in most cases.

    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.

    That is the case for its potential usefulness in static error checking,
    but not the case for its potential usefulness in optimisation.

    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.

    This is why some compilers and other verification tools have extensions
    that can do more than "static" array parameters can - gcc's "access"
    attribute and "object size" builtins are examples.

    Still, even if it only helps occasionally, that's better than no help at
    all.



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From David Brown@3:633/280.2 to All on Tue May 13 01:18:06 2025
    On 12/05/2025 11:27, Keith Thompson wrote:
    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.


    Sure. If gcc had a warning enforcing such consistency, I would
    definitely use it.

    But not all C programmers are as pedantic about consistency between a
    function declaration and definition. It is not uncommon to be
    inconsistent about the names of parameters (or even if the parameters
    have names at all), or mixing array-style parameters and pointer-style parameters.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From David Brown@3:633/280.2 to All on Tue May 13 01:24:16 2025
    On 12/05/2025 11:23, 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:
    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.)


    The UB is actually at the function call site, rather than in the
    function itself. Thus adding a "static N" to the function definition
    can change the semantics of the call site:

    // file1.c
    extern int foo(int * p);

    int bar(void) {
    int xs[4];
    return foo(xs);
    }

    // file2.c
    #define N 4

    int foo(int p[static N]) {
    return 42;
    }



    Changing "N" to 5 will render the call in file1.c undefined behaviour,
    without having any semantic effect on the function definition in file2.c




    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Keith Thompson@3:633/280.2 to All on Tue May 13 06:31:47 2025
    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.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: None to speak of (3:633/280.2@fidonet)
  • From Keith Thompson@3:633/280.2 to All on Tue May 13 06:38:46 2025
    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.)

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: None to speak of (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Tue May 13 09:53:14 2025
    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. The violation would have
    to be detected in the code that sets the pointer's value before passing
    it, directly or indirectly, to the function with a "static" array length.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Tue May 13 12:04:20 2025
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    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.

    I need to correct myself. This statement is simply wrong. Giving a
    parameter declarator a 'static' length specification, as part of any
    function declaration whatsoever, has the same effect as it would if
    it had been given on the function definition. To present an example,
    if we have three source files, x.c, y.c, and z.c, with

    /* x.c */
    int foo( int v[] );

    int
    example(){
    return foo( 0 );
    }


    /* y.c */
    int
    foo( int v[] ){
    return v ? v[0] : -1;
    }


    /* z.c */
    int foo( int v[ static 1 ] );


    then because of the declaration of foo() in z.c, the call to foo()
    in x.c has undefined behavior, because a "shall" requirement is
    violated by passing a null pointer for parameter v, which must
    point to an array with at least one element.

    As best I can determine the description of how 'static' works in
    such cases has not changed since its original introduction in C99
    up to the present.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Tue May 13 15:42:30 2025
    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. Certainly I would say you
    have your own views and opinions, and many of them strongly
    held. But that isn't the same as what I mean by self-centered.
    I don't think of you as being self-centered in the same sense
    as what I was trying to say above.

    (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.)

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Tue May 13 16:03:59 2025
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    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.
    [...]

    An implementation could issue a diagnostic whenever it could
    determine that the requirement had been violated, and also
    whenever it could not establish that the requirement was
    satisfied. A message like

    "this call to function foo() might not supply a large enough
    array to satisfy an array static length requirement".

    would, I think, satisfy the letter of the rule that any constraint
    violation must result in at least one diagnostic being produced.

    Granted, I think most people would find such behavior more
    annoying than useful, but it does seem to be a way to meet the
    stipulations for constraint violations, in letter even if not in
    spirit.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Richard Heathfield@3:633/280.2 to All on Tue May 13 16:31:06 2025
    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.

    Keith's a big lad. He doesn't need me to defend him. But neither
    does he need you to attack him.

    --
    Richard Heathfield
    Email: rjh at cpax dot org dot uk
    "Usenet is a strange place" - dmr 29 July 1999
    Sig line 4 vacant - apply within


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: Fix this later (3:633/280.2@fidonet)
  • From David Brown@3:633/280.2 to All on Tue May 13 20:41:22 2025
    On 12/05/2025 22:38, Keith Thompson wrote:
    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.)


    Certainly compilers are more likely to be able to differentiate between
    null values and non-null values, than between pointers to different
    lengths of data. So yes, this can be a useful check.

    For my own use, I dislike this syntax - if I want a pointer to an int, I prefer to give the parameter the form pointer to an int. The array form
    might mean the same thing to the compiler, but it does not give the same clarity to the human programmer. And if I want extra checking on this
    kind of thing, I use gcc attributes. (Of course not all programmers can
    do that, or want to do that, in their code.)


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Janis Papanagnou@3:633/280.2 to All on Tue May 13 23:57:00 2025
    On 12.05.2025 02:30, Tim Rentsch wrote:
    [...]

    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. [...]

    This is an interesting proposal.

    When was it suggested, and what is the decision state?

    What were the arguments, pros and cons?

    Janis


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Wed May 14 02:30:55 2025
    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.

    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.

    I have two more short comments to add.

    One, I have no desire to start a fight, or engage in one.

    Two, I mean to observe a distinction between self-centered and
    selfish. These two words mean different things.

    Also let me add, parenthetically, in most cases I consider it
    bad manners to discuss a third party in a public forum. (That
    is not meant as a criticism of your commment, which I take to
    be a sincere interest in everyone's well being.) I don't mind
    responding to your comments but I don't expect to say anything
    specifically about Keith.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Janis Papanagnou@3:633/280.2 to All on Wed May 14 06:28:25 2025
    On 12.05.2025 16:34, Richard Heathfield wrote:
    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.

    It's a social and psychological theme; when a topic gets in a personal direction and getting disrespectful and that is publicly exchanged the
    response (defense or counterstrike) is likely also continued where the
    "attack" had taken place. That bickering doesn't go ad infinitum but
    it at least leads to long and deep threads (with little value). If the disputants have a strong backbone - any many here have - it's getting difficult. But I sense occasional attempts to soothe the situations
    and thus interrupt the [perceived] endless process.

    f() { g(); }
    g() { f(); }

    without an appropriate 'if' will not be good. An alternative is to not
    start that process by f() or g() in the first place. - Just an attempt
    to have this meta-topic getting a bit "C"-like. Feel free to ignore it.
    :-p

    Janis


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Janis Papanagnou@3:633/280.2 to All on Wed May 14 07:16:49 2025
    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

    [...]



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Keith Thompson@3:633/280.2 to All on Wed May 14 07:35:06 2025
    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 (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: None to speak of (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Wed May 14 08:10:56 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    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.

    In N1570, 6.7.6.3 p7.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Keith Thompson@3:633/280.2 to All on Wed May 14 08:41:36 2025
    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? I don't see how it does either.

    """
    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 (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: None to speak of (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Wed May 14 11:38:32 2025
    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)'.

    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.

    That isn't what the C standard says. It just says "array", not
    "array object".

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Keith Thompson@3:633/280.2 to All on Wed May 14 12:37:53 2025
    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.)

    [snip]

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: None to speak of (3:633/280.2@fidonet)
  • From Kaz Kylheku@3:633/280.2 to All on Wed May 14 13:35:27 2025
    On 2025-05-13, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    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 haven't found explicit wording which supports the concept in the above use scenario.

    The Library clause (I'm referring to n3301 here0 has the wording:

    If a function argument is described as being an array, the pointer passed to
    the function shall have a value such that all address computations and
    accesses to objects (that would be valid if the pointer did point to the first
    element of such an array) are valid.(218)

    Footnote 218 gives some degenerate examples more extreme than the
    arr + 5 situation:

    This includes, for example, passing a valid pointer that points
    one-past-the-end of an array along with a size of 0, or using any valid
    pointer with a size of 0.

    The presence of the wording in the Library clause suggests that someone though it was necessary. It needs to be extended (or repeated elsewhere with adjusted wording) to cover situations involving language constructs that are not standard library functions.

    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.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Wed May 14 13:54:36 2025
    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 - you very commonly post messages leaving out lots of relevant
    information, seemingly expecting people to figure out the details that
    you don't bother to provide. This can be a valid teaching technique, but
    using that technique relies on the assumption that what you've left out
    can be determined by careful examination of what you put in. However,
    Keith had no reasonable way of guessing what you had left out, because
    he did not anticipate that you would address the wrong question. As a
    general rule, if there's any possibility that you've made a mistake like
    you did in this case, leaving out too many details as "an exorcise for
    the student" runs the risk of not not providing enough information for
    others to identify and correct the mistake.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Wed May 14 14:12:53 2025
    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.

    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.)

    The wording of 6.7.6.3 p7 was carefully chosen so that it would allow
    cases like 'func(arr+5)', for the same reasons that it would deem
    'func(arr+6)' as being undefined behavior.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Wed May 14 14:19:54 2025
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    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 - [...]

    I don't know why you expect me to read postings meant for me but
    posted as a reply to another poster. Sometimes I do, sometimes
    I don't. You may take the correlation as being determined by
    quantum mechanical uncertainty.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Keith Thompson@3:633/280.2 to All on Wed May 14 14:54:22 2025
    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.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: None to speak of (3:633/280.2@fidonet)
  • From Keith Thompson@3:633/280.2 to All on Wed May 14 15:38:11 2025
    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:
    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.

    Again, of course the behavior of func(arr+6) is undefined. The behavior
    of func(arr+5) is less clear *to me*.

    """
    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.

    It does so only if the argument arr+5 provides access to "the first
    element of an array". You seem to think that it's obvious that it does
    so, based on the disinction you make between "array" and "array object".

    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.

    I note that you haven't answered the above questions. They were not rhetorical. I asked them because I thought that answers to those
    specific questions would help me to understand the distinction that you
    make between "array" and "array object".

    The meanings follow from a plain understanding of the English
    language.

    I disagree. Perhaps my understanding of certain combinations of English
    words differs from yours.

    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.

    Is there no "region of data storage in the execution environment, the
    contents of which can represent values"? Cannot that region represent
    a value of type unsigned char[sizeof(T)-1]? Is a region of data
    storage that can represent values of array type not an array object?
    Again, none of these questions are rhetorical.

    Can you define, preferably in something approaching standardese, what
    you mean by "array" and by "array object", and in particular how they
    differ?

    I believe that, in my example above, arr+5 *does* "provide access
    to an array" with at least 5 elements. (I also believe that that
    "array" is an "array object".) My difficulty is in demonstrating
    this based on the normative wording in the standard. *Maybe*
    if you could explain the distinction you make between "array" and
    "array object" it would help.

    [...]

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: None to speak of (3:633/280.2@fidonet)
  • From Kaz Kylheku@3:633/280.2 to All on Wed May 14 16:31:01 2025
    On 2025-05-14, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    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.

    This issue with a + 5 and all points to a more general issue.
    There is no discussion about aliasing between arrays of
    the same element type, but different sizes and displacements.

    Given int a[10], we can do int (*p)[5] = (int (*)[5])(a + 5) to obtain
    a pointer the upper half of the array as an int [5] array type.

    Then *p is an array lvalue which recovers us a + 5.
    Surely, that is valid; but it's not spelled out.

    Arrays are not accessed themselves since they cannot be passed,
    returned or assigned, and their values "decay" to pointers.

    An access like (*p)[1] cannot be considered an invalid aliasing for
    a[6], since it uses the declared type of the element. The pointer is
    valid, and not by chance; but doe to good arithmetic
    on a good starting value.

    *p itself cannot be invalid aliasing because that concept is defined in
    terms of access using the wrong type, and *p doesn't access.

    (And so, why couldn't we pass the expression *p as the argument to that
    int a[static 5]? If *p doesn't count as an array, by what
    rule is that? Surely not aliasing. And if *p is okay but a + 5 is not,
    what's the point of the hair-splititng.)

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From David Brown@3:633/280.2 to All on Wed May 14 21:00:51 2025
    On 13/05/2025 23:35, Keith Thompson wrote:
    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.


    My interpretation matches yours. I can't find any indication in the
    standard of a definition of what an "array" actually means. It would be extraordinary - and render vast amounts of C code as having undefined behaviour - if "arr + 5" above could not be considered as pointing to
    the first element of an array of 5 int. (I believe the same logic
    applies to pointer arithmetic in general - not just this specific
    situation.) But that does not imply that the standard says a pointer to
    an element inside an array or array object can be treated as a pointer
    to the first element of an array and/or array object of appropriate size.

    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.



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Janis Papanagnou@3:633/280.2 to All on Wed May 14 21:20:57 2025
    On 14.05.2025 13:00, David Brown wrote:
    [...]

    I believe we can reassure Janis that your example code will be
    considered valid by any real-world compiler.

    Thanks. Much appreciated. (I wasn't sure after some postings that were
    a bit distracting and thus more muddying the topic than clarifying.)

    But it would be nice to
    find some combination of standard paragraphs that guarantee it.

    Yes, indeed. (Heuristics are fine but certainty is better.)

    Janis


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Thu May 15 04:09:51 2025
    Michael S <already5chosen@yahoo.com> writes:

    (I am summarizing heavily in an effort to return to the main area
    of interest.)

    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]

    I did a more comprehensive gathering of statistics, using an ad hoc
    collection of 68 open source projects, ranging in size from just
    over 1500 lines to over a million lines, including two outliers
    with 20 million lines and 75 million lines. The ratio of while()
    to do/while() ranged from 12.5% to 2100%, with an average of
    573.9%. The ratio of while() to for() ranged from 1.6% to 300%,
    with an average of 60.8%.

    [...] while() does not help anything relatively to for().

    I understand that that is your view. I don't remember seeing any
    supporting statements other than your personal reactions. My own
    experience is different. Judging by the open source statistics
    reported above, it appears that a fair number of other developers
    don't share your views on this question either.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From James Kuyper@3:633/280.2 to All on Thu May 15 13:20:48 2025
    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".


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Thu May 15 13:44:54 2025
    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:

    [...]

    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.

    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.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Thu May 15 14:12:21 2025
    Richard Heathfield <rjh@cpax.org.uk> writes:

    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.

    I responded twice to your earlier message. I want to acknowledge this
    later message and respond here in an effort to achieve some closure.

    I appreciate the intention of your two followups. It isn't easy to
    play the role of peacemaker, especially in comp.lang.c, and I think
    your comments are helping cool things down. Thank you for that.

    Clearly there have been some misunderstandings. I think it would
    be a real effort to unwind those (even assuming that they have all
    been identified), and besides this isn't the right venue at least
    for some of them. So I don't have more to say about that except
    to say I am making an effort to do better in the future.

    Thank you again for trying to help.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Keith Thompson@3:633/280.2 to All on Thu May 15 14:45:03 2025
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    [...]
    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.

    Thank you.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: None to speak of (3:633/280.2@fidonet)
  • From David Brown@3:633/280.2 to All on Thu May 15 19:23:04 2025
    On 15/05/2025 05:20, James Kuyper wrote:
    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".


    Yes, I agree.

    I guess that's why they call c.l.c. regulars who discuss these things "language lawyers"! Now all we need to do is find a way to get paid
    like lawyers...


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Tim Rentsch@3:633/280.2 to All on Tue Jun 10 23:01:20 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    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.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Sat Jun 14 20:24:30 2025
    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.
    Little-endian is simply the cleverer idea.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Scott Lurndal@3:633/280.2 to All on Sat Jun 14 23:57:56 2025
    Reply-To: slp53@pacbell.net

    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.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: UsenetServer - www.usenetserver.com (3:633/280.2@fidonet)
  • From Michael S@3:633/280.2 to All on Sun Jun 15 05:27:20 2025
    On Sat, 14 Jun 2025 13:57:56 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:

    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.


    802.3 frames are big-endian, because of Length field.
    Several orders of magnitude more popular Ethernet II frames are
    endian-neutral.


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Sun Jun 15 17:32:39 2025
    Am 14.06.2025 um 15:57 schrieb Scott Lurndal:
    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.

    However, little-endian is simply the smarter concept.

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)