What do you think of this control block?
 do
 {
    FILE f = fopen("file.txt", "r");
    if (f == NULL) quit; /*goes to else part*/
    /*success here*/
    for (int i =0; i < 10; i++){
        ...
        if (error) quit;
    }
 }
 else
 {
    /*some error*/
 }
What do you think of this control block?
do
{
FILE f = fopen("file.txt", "r");
if (f == NULL) quit; /*goes to else part*/
/*success here*/
for (int i =0; i < 10; i++){
...
if (error) quit;
}
}
else
{
/*some error*/
}
On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
What do you think of this control block?
do
{
FILE f = fopen("file.txt", "r");
if (f == NULL) quit; /*goes to else part*/
/*success here*/
for (int i =0; i < 10; i++){
...
if (error) quit;
}
}
else
{
/*some error*/
}
The else part might need access to some local variables
in the main part.
do {
char *name = calculate_path(PATH_PREFIX "/", name, ".txt");
FILE *f = fopen(...)
if (!f)
quit;
...
}
else
{
printf("unable to open %s\n", name);
...
}
If you make that work, you're creating scope wormholes between
disjoint curly braces, which is not allowed if youre name isn't
Bjarne Stroustrup.
What do you think of this control block?
do
{
FILE f = fopen("file.txt", "r");
if (f == NULL) quit; /*goes to else part*/
/*success here*/
for (int i =0; i < 10; i++){
...
if (error) quit;
}
}
else
{
/*some error*/
}
Em 4/4/2025 5:34 PM, Kaz Kylheku escreveu:
The else part might need access to some local variables
in the main part.
do {
char *name = calculate_path(PATH_PREFIX "/", name, ".txt");
FILE *f = fopen(...)
if (!f)
quit;
...
}
else
{
printf("unable to open %s\n", name);
...
}
In this case we move the scope of the variable we need.
On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
What do you think of this control block?
do
{
FILE f = fopen("file.txt", "r");
if (f == NULL) quit; /*goes to else part*/
/*success here*/
for (int i =0; i < 10; i++){
...
if (error) quit;
}
}
else
{
/*some error*/
}
The else part might need access to some local variables
in the main part.
Kaz Kylheku <643-408-1753@kylheku.com> writes:
On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
What do you think of this control block?
[...]
I don't believe C++ exceptions are useful in this case, either,
and I avoid using them for general purpose error handling.
On 05.04.2025 16:54, Scott Lurndal wrote:
Kaz Kylheku <643-408-1753@kylheku.com> writes:
On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
What do you think of this control block?
[...]
I don't believe C++ exceptions are useful in this case, either,
and I avoid using them for general purpose error handling.
I'd have wished that they were available back then when we
started using C++ regularly in the early 1990's.
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
On 05.04.2025 16:54, Scott Lurndal wrote:
Kaz Kylheku <643-408-1753@kylheku.com> writes:
On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
What do you think of this control block?
[...]
I don't believe C++ exceptions are useful in this case, either,
and I avoid using them for general purpose error handling.
I'd have wished that they were available back then when we
started using C++ regularly in the early 1990's.
I was using C++ (cfront 2.1) for operating system code in 1990.
We couldn't have used exceptions even when they were introduced
in cfront 3 for that project.
I strongly believe errors must be handled immediately when
detected, rather than deferring to some nebulous code a long
way in both space and time from the actual error.
The only use I see for C++ exceptions is a cleaner
sigsetjmp/siglongjmp, and even then I've used
the later when the former is available. As an
experiment, I once replaced the sigsetjmp/siglongjmp
calls with C++ exceptions and found that using exceptions
reduced application performance by a double-digit percentage
for that particular applications (processor simulator).
What do you think of this control block?
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
On 05.04.2025 16:54, Scott Lurndal wrote:
Kaz Kylheku <643-408-1753@kylheku.com> writes:
On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
What do you think of this control block?
[...]
I don't believe C++ exceptions are useful in this case, either,
and I avoid using them for general purpose error handling.
I'd have wished that they were available back then when we
started using C++ regularly in the early 1990's.
I was using C++ (cfront 2.1) for operating system code in 1990.
We couldn't have used exceptions even when they were introduced
in cfront 3 for that project.
I strongly believe errors must be handled immediately when
detected, rather than deferring to some nebulous code a long
way in both space and time from the actual error.
The only use I see for C++ exceptions is a cleaner
sigsetjmp/siglongjmp, and even then I've used
the later when the former is available. As an
experiment, I once replaced the sigsetjmp/siglongjmp
calls with C++ exceptions and found that using exceptions
reduced application performance by a double-digit percentage
for that particular applications (processor simulator).
 What do you think of this control block?
 do
 {
    FILE f = fopen("file.txt", "r");
    if (f == NULL) quit; /*goes to else part*/
    /*success here*/
    for (int i =0; i < 10; i++){
        ...
        if (error) quit;
    }
 }
 else
 {
    /*some error*/
 }
Em 4/4/2025 5:48 PM, Tim Rentsch escreveu:
Thiago Adams <thiago.adams@gmail.com> writes:
What do you think of this control block?
do
{
FILE f = fopen("file.txt", "r");
if (f == NULL) quit; /*goes to else part*/
/*success here*/
for (int i =0; i < 10; i++){
...
if (error) quit;
}
}
else
{
/*some error*/
}
I think it doesn't belong in comp.lang.c.
I also think you have been participating in comp.lang.c
long enough to know better. Kindly take your language
fantasies somewhere else.
I think the only reason you're saying that is because it's not
implemented in GCC, Clang, or maybe even MSVC.
I've never seen you complain about any GCC extensions here.
Thiago Adams <thiago.adams@gmail.com> writes:
Em 4/4/2025 5:48 PM, Tim Rentsch escreveu:
Thiago Adams <thiago.adams@gmail.com> writes:
What do you think of this control block?
do
{
FILE f = fopen("file.txt", "r");
if (f == NULL) quit; /*goes to else part*/
/*success here*/
for (int i =0; i < 10; i++){
...
if (error) quit;
}
}
else
{
/*some error*/
}
I think it doesn't belong in comp.lang.c.
I also think you have been participating in comp.lang.c
long enough to know better. Kindly take your language
fantasies somewhere else.
I think the only reason you're saying that is because it's not
implemented in GCC, Clang, or maybe even MSVC.
You are wrong. I responded because there is nothing in
your posting that is suitable for comp.lang.c.
I've never seen you complain about any GCC extensions here.
I don't remember seeing any posting in comp.lang.c that
discusses a gcc extension and nothing else. There are
plenty of postings that mention gcc extensions in passing,
along with other material that talks about C, but never
one that discusses gcc extensions exclusively.
Furthermore, even if there had been a posting that concerns
only a gcc extension and nothing else, and is one I didn't
respond to, that doesn't excuse your action. It isn't like
this is the first time you have posted something here that
is not about C but only about your fantasy language, and
also not the first time the unsuitability of such postings
has been pointed out. You're a repeat offender. So stop
pretending you are being picked on for no reason.
More interesting question than the one above is: why post of Alexis
from 3 months ago named "Opinion on defer" is on topic in c.l.c ?
How exactly can we draw a line between two cases?
Thiago Adams <thiago.adams@gmail.com> writes:
Em 4/4/2025 5:48 PM, Tim Rentsch escreveu:
Thiago Adams <thiago.adams@gmail.com> writes:
What do you think of this control block?
do
{
FILE f = fopen("file.txt", "r");
if (f == NULL) quit; /*goes to else part*/
/*success here*/
for (int i =0; i < 10; i++){
...
if (error) quit;
}
}
else
{
/*some error*/
}
I think it doesn't belong in comp.lang.c.
I also think you have been participating in comp.lang.c
long enough to know better. Kindly take your language
fantasies somewhere else.
I think the only reason you're saying that is because it's not
implemented in GCC, Clang, or maybe even MSVC.
You are wrong. I responded because there is nothing in
your posting that is suitable for comp.lang.c.
I've never seen you complain about any GCC extensions here.
I don't remember seeing any posting in comp.lang.c that
discusses a gcc extension and nothing else. There are
plenty of postings that mention gcc extensions in passing,
along with other material that talks about C, but never
one that discusses gcc extensions exclusively.
Furthermore, even if there had been a posting that concerns
only a gcc extension and nothing else, and is one I didn't
respond to, that doesn't excuse your action. It isn't like
this is the first time you have posted something here that
is not about C but only about your fantasy language, and
also not the first time the unsuitability of such postings
has been pointed out. You're a repeat offender. So stop
pretending you are being picked on for no reason.
On Sun, 06 Apr 2025 05:47:47 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Thiago Adams <thiago.adams@gmail.com> writes:
Em 4/4/2025 5:48 PM, Tim Rentsch escreveu:
Thiago Adams <thiago.adams@gmail.com> writes:
What do you think of this control block?
do
{
FILE f = fopen("file.txt", "r");
if (f == NULL) quit; /*goes to else part*/
/*success here*/
for (int i =0; i < 10; i++){
...
if (error) quit;
}
}
else
{
/*some error*/
}
I think it doesn't belong in comp.lang.c.
I also think you have been participating in comp.lang.c
long enough to know better. Kindly take your language
fantasies somewhere else.
I think the only reason you're saying that is because it's not
implemented in GCC, Clang, or maybe even MSVC.
You are wrong. I responded because there is nothing in
your posting that is suitable for comp.lang.c.
I've never seen you complain about any GCC extensions here.
I don't remember seeing any posting in comp.lang.c that
discusses a gcc extension and nothing else. There are
plenty of postings that mention gcc extensions in passing,
along with other material that talks about C, but never
one that discusses gcc extensions exclusively.
Furthermore, even if there had been a posting that concerns
only a gcc extension and nothing else, and is one I didn't
respond to, that doesn't excuse your action. It isn't like
this is the first time you have posted something here that
is not about C but only about your fantasy language, and
also not the first time the unsuitability of such postings
has been pointed out. You're a repeat offender. So stop
pretending you are being picked on for no reason.
Could you recommend a more appropriate place for Thiago and others
where they can discuss C-like fantasy languages?
On Sat, 05 Apr 2025 16:10:36 GMT
scott@slp53.sl.home (Scott Lurndal) wrote:
If you believe in non-trivial constructors (i.e. constructors that can
fail) then you have to believe in exceptions as well.
Personally, I don't believe in either.
But then, I don't believe that C++ is suitable for for operating system >code...
More interesting question than the one above is: why post of Alexis
from 3 months ago named "Opinion on defer" is on topic in c.l.c ?
How exactly can we draw a line between two cases?
On 05.04.2025 18:10, Scott Lurndal wrote:
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
On 05.04.2025 16:54, Scott Lurndal wrote:
Kaz Kylheku <643-408-1753@kylheku.com> writes:
On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
What do you think of this control block?
[...]
I don't believe C++ exceptions are useful in this case, either,
and I avoid using them for general purpose error handling.
I'd have wished that they were available back then when we
started using C++ regularly in the early 1990's.
I was using C++ (cfront 2.1) for operating system code in 1990.
We couldn't have used exceptions even when they were introduced
in cfront 3 for that project.
I strongly believe errors must be handled immediately when
detected, rather than deferring to some nebulous code a long
way in both space and time from the actual error.
There's nothing deferred with exceptions. Unless you defer it.
The only use I see for C++ exceptions is a cleaner
sigsetjmp/siglongjmp, and even then I've used
the later when the former is available. As an
experiment, I once replaced the sigsetjmp/siglongjmp
calls with C++ exceptions and found that using exceptions
reduced application performance by a double-digit percentage
for that particular applications (processor simulator).
I think one fundamental problem here is that you started with a
primitive low level "exit-concept"; refactoring such structures
is likely doomed to fail.
In article <20250406162607.0000657a@yahoo.com>,
Michael S <already5chosen@yahoo.com> wrote:
...
More interesting question than the one above is: why post of Alexis
from 3 months ago named "Opinion on defer" is on topic in c.l.c ?
How exactly can we draw a line between two cases?
Tim Wrench is clearly a lunatic. And he's in my killfile.
The language he uses in this thread is just beyond the pale (*) in terms of rudeness and non-civility. If his target was anyone else (and especially
if it was an old regular), we'd probably have 20 posts already condemning
his language.
(*) I think that's the right spelling - for a phrase I've only heard and
have never seen written down. Or is it "pail" ?
On Sun, 06 Apr 2025 05:47:47 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Thiago Adams <thiago.adams@gmail.com> writes:
Em 4/4/2025 5:48 PM, Tim Rentsch escreveu:
Thiago Adams <thiago.adams@gmail.com> writes:
What do you think of this control block?
do
{
FILE f = fopen("file.txt", "r");
if (f == NULL) quit; /*goes to else part*/
/*success here*/
for (int i =0; i < 10; i++){
...
if (error) quit;
}
}
else
{
/*some error*/
}
I think it doesn't belong in comp.lang.c.
I also think you have been participating in comp.lang.c
long enough to know better. Kindly take your language
fantasies somewhere else.
I think the only reason you're saying that is because it's not
implemented in GCC, Clang, or maybe even MSVC.
You are wrong. I responded because there is nothing in
your posting that is suitable for comp.lang.c.
I've never seen you complain about any GCC extensions here.
I don't remember seeing any posting in comp.lang.c that
discusses a gcc extension and nothing else. There are
plenty of postings that mention gcc extensions in passing,
along with other material that talks about C, but never
one that discusses gcc extensions exclusively.
Furthermore, even if there had been a posting that concerns
only a gcc extension and nothing else, and is one I didn't
respond to, that doesn't excuse your action. It isn't like
this is the first time you have posted something here that
is not about C but only about your fantasy language, and
also not the first time the unsuitability of such postings
has been pointed out. You're a repeat offender. So stop
pretending you are being picked on for no reason.
More interesting question than the one above is: why post of
Alexis from 3 months ago named "Opinion on defer" is on topic in
c.l.c ?
How exactly can we draw a line between two cases?
Michael S <already5chosen@yahoo.com> writes:
On Sun, 06 Apr 2025 05:47:47 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Furthermore, even if there had been a posting that concerns
only a gcc extension and nothing else, and is one I didn't
respond to, that doesn't excuse your action. It isn't like
this is the first time you have posted something here that
is not about C but only about your fantasy language, and
also not the first time the unsuitability of such postings
has been pointed out. You're a repeat offender. So stop
pretending you are being picked on for no reason.
Could you recommend a more appropriate place for Thiago and others
where they can discuss C-like fantasy languages?
The newsgroup comp.lang.misc seems like a natural candidate.
I don't know if comp.lang.misc has an official charter, but at
least to me new features of any widely used programming language
would appear to fall under the umbrella of comp.lang.misc.
My impression was that "defer", or something very much like it, is
being considered for inclusion in a future C standard. Isn't it the
case that Jens Gustedt is now the head of the C standard committee?
Of course I might be wrong about that, but that's what I thought
(and probably will still think unless and until I hear otherwise).
A number of regulars here have responded (with posts other than "this
is off-topic"), so that suggests there is at least some interest in
the group.
On Sun, 06 Apr 2025 08:14:19 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
My impression was that "defer", or something very much like it, is
being considered for inclusion in a future C standard. Isn't it the
case that Jens Gustedt is now the head of the C standard committee?
Of course I might be wrong about that, but that's what I thought
(and probably will still think unless and until I hear otherwise).
It seems, The WG14 Committee has no head. They have Convener (Robert
Seacord) but that is probably not the same.
Jens Gustedt appears to be one of the most active members.
https://www.open-std.org/jtc1/sc22/wg14/
David Brown <david.brown@hesbynett.no> wrote:
A number of regulars here have responded (with posts other than "this
is off-topic"), so that suggests there is at least some interest in
the group.
I like to see such things discussed here. If it looks like there is a
need for new constructs, the thread(s) may end with acceptable
alternatives using only current C's capabilities.
Other times a pre-compiler might add some icing on the C cake. I'd
prefer that way over touching the standard.
With changes to C directly, I'd be very conservative. Far too often I already stumble over stuff that isn't buildable with current compilers
any more. Try even to build some older GCC with the current ones.
Imo we do not do us a favour if the incompatibilities pile up to a level
that ends with C != C, but it already seems too late to stop this.
On Sun, 06 Apr 2025 08:14:19 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
My impression was that "defer", or something very much like it, is
being considered for inclusion in a future C standard. Isn't it the
case that Jens Gustedt is now the head of the C standard committee?
Of course I might be wrong about that, but that's what I thought
(and probably will still think unless and until I hear otherwise).
It seems, The WG14 Committee has no head. They have Convener (Robert Seacord) but that is probably not the same.
Jens Gustedt appears to be one of the most active members.
https://www.open-std.org/jtc1/sc22/wg14/
On Sun, 06 Apr 2025 07:32:16 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 06 Apr 2025 05:47:47 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Furthermore, even if there had been a posting that concerns
only a gcc extension and nothing else, and is one I didn't
respond to, that doesn't excuse your action. It isn't like
this is the first time you have posted something here that
is not about C but only about your fantasy language, and
also not the first time the unsuitability of such postings
has been pointed out. You're a repeat offender. So stop
pretending you are being picked on for no reason.
Could you recommend a more appropriate place for Thiago and others
where they can discuss C-like fantasy languages?
The newsgroup comp.lang.misc seems like a natural candidate.
I don't know if comp.lang.misc has an official charter, but at
least to me new features of any widely used programming language
would appear to fall under the umbrella of comp.lang.misc.
My question was not completely abstract.
I did consider starting a discussion about possibility of inclusion of stackless co-routines into one of the future editions of C.
Naturally, my ideas at this state are extremely in-concrete, much more
so then the post of Thiago Adams that started this thread.
So, if I ever come to it, which by itself is not very likely, do you
think that comp.lang.misc would be better place than comp.lang.c ?
In article <20250406162607.0000657a@yahoo.com>,
Michael S <already5chosen@yahoo.com> wrote:
...
More interesting question than the one above is: why post of Alexis
from 3 months ago named "Opinion on defer" is on topic in c.l.c ?
How exactly can we draw a line between two cases?
Tim Wrench is clearly a lunatic. And he's in my killfile.
The language he uses in this thread is just beyond the pale (*) in
terms of rudeness and non-civility. If his target was anyone else
(and especially if it was an old regular), we'd probably have 20
posts already condemning his language.
Michael S <already5chosen@yahoo.com> writes:
On Sun, 06 Apr 2025 07:32:16 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 06 Apr 2025 05:47:47 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Furthermore, even if there had been a posting that concerns
only a gcc extension and nothing else, and is one I didn't
respond to, that doesn't excuse your action. It isn't like
this is the first time you have posted something here that
is not about C but only about your fantasy language, and
also not the first time the unsuitability of such postings
has been pointed out. You're a repeat offender. So stop
pretending you are being picked on for no reason.
Could you recommend a more appropriate place for Thiago and others
where they can discuss C-like fantasy languages?
The newsgroup comp.lang.misc seems like a natural candidate.
I don't know if comp.lang.misc has an official charter, but at
least to me new features of any widely used programming language
would appear to fall under the umbrella of comp.lang.misc.
My question was not completely abstract.
I did consider starting a discussion about possibility of inclusion
of stackless co-routines into one of the future editions of C.
Naturally, my ideas at this state are extremely in-concrete, much
more so then the post of Thiago Adams that started this thread.
So, if I ever come to it, which by itself is not very likely, do you
think that comp.lang.misc would be better place than comp.lang.c ?
Before giving an answer I would like to ask some questions.
* How much does the (still fuzzy) idea depend on running in a C
environment? Is it very specific to C, or might it be applicable
to other procedural/imperative languages (for example, Pascal)?
* How much does the current C language impact what you expect to
propose? Which aspects of C need to be taken into consideration
in forming the proposal, and how strongly do those considerations
affect the specifics of what would be proposed?
* Assuming a proposed extension has been fully worked out, how
broad or how narrow do you think the interest would be in the
general C community for a future C standard to incorporate the
proposed extension?
* Assuming you get to a point where you are happy with the details
of a proposed extension, how likely is it that you would write a
proposal for the C standard committee, and make the effort needed
to shepherd it through the process of being accepted for a future
C standard?
I realize you probably don't have firm answers for some or all of
these questions. As part of figuring everything out, you might want
to start a discussion both of the general idea and also about what
the answers to these questions might be. I think comp.lang.misc is
a good place to have such a discussion, even if your ideas are still
in the process of being formed; the discussion could then serve the
dual purpose of getting the idea fleshed out and of determining how
strongly the idea should be considered as part of a future C
standard.
On Mon, 07 Apr 2025 05:45:19 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 06 Apr 2025 07:32:16 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 06 Apr 2025 05:47:47 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Furthermore, even if there had been a posting that concerns
only a gcc extension and nothing else, and is one I didn't
respond to, that doesn't excuse your action. It isn't like
this is the first time you have posted something here that
is not about C but only about your fantasy language, and
also not the first time the unsuitability of such postings
has been pointed out. You're a repeat offender. So stop
pretending you are being picked on for no reason.
Could you recommend a more appropriate place for Thiago and others
where they can discuss C-like fantasy languages?
The newsgroup comp.lang.misc seems like a natural candidate.
I don't know if comp.lang.misc has an official charter, but at
least to me new features of any widely used programming language
would appear to fall under the umbrella of comp.lang.misc.
My question was not completely abstract.
I did consider starting a discussion about possibility of inclusion
of stackless co-routines into one of the future editions of C.
Naturally, my ideas at this state are extremely in-concrete, much
more so then the post of Thiago Adams that started this thread.
So, if I ever come to it, which by itself is not very likely, do you
think that comp.lang.misc would be better place than comp.lang.c ?
Before giving an answer I would like to ask some questions.
* How much does the (still fuzzy) idea depend on running in a C
environment? Is it very specific to C, or might it be applicable
to other procedural/imperative languages (for example, Pascal)?
* How much does the current C language impact what you expect to
propose? Which aspects of C need to be taken into consideration
in forming the proposal, and how strongly do those considerations
affect the specifics of what would be proposed?
Of course, proposals for similar feature in other procedural/imperative language would not be totally different. Pascal is more similar to C
than many other procedural languages, so solution for Pascal would
likely be more similar to C than for example, stackless co-routines
that already exist in such languages like C# (that started current wave
of popularity of the feature) or Python.
However Pascal and C have enough not in common for significant
difference in proposed syntax and implementation. Specifically, in
Pascal:
- heap management is built-n in the language
- non-local goto is built-n in the language
- nested procedures
- everything related to separated compilation of the translation units
is handwaved in the docs rather than strictly specified.
May be it's
not so in Extended Pascal standard, I never read it.
Most importantly, Pascal in its hay days had different (from C)
attitude with regard to standardization. Implementors, especially
bigger ones, freely made very significant mutually incompatible
extensions and nobody in community was upset about it. C way is more centralized.
On 07/04/2025 19:02, Michael S wrote:
On Mon, 07 Apr 2025 05:45:19 -0700
Of course, proposals for similar feature in other procedural/imperative
language would not be totally different. Pascal is more similar to C
than many other procedural languages, so solution for Pascal would
likely be more similar to C than for example, stackless co-routines
that already exist in such languages like C# (that started current wave
of popularity of the feature) or Python.
However Pascal and C have enough not in common for significant
difference in proposed syntax and implementation. Specifically, in
Pascal:
- heap management is built-n in the language
- non-local goto is built-n in the language
That's news to me. But then I only used an educational version.
- nested procedures
- everything related to separated compilation of the translation units
is handwaved in the docs rather than strictly specified.
I don't think it's that strictly specified in C. Isn't it vaguely left
to the implementation?
Much of how different units share macros, types, structs and enums isn't
part of the language at all AFAICS: it's just a by-product of different modules happening to include the same header files.
But it could also be done by repeating declarations in each module; it's rather ad hoc.
The Pascal I used only worked with one module; more recent versions do
seem to have formal interfaces which are part of the language. So it is
more rigorous than C.
May be it's
not so in Extended Pascal standard, I never read it.
Most importantly, Pascal in its hay days had different (from C)
attitude with regard to standardization. Implementors, especially
bigger ones, freely made very significant mutually incompatible
extensions and nobody in community was upset about it. C way is more
centralized.
I have a feeling that there were WAY more variations of C than Pascal, largely because C was more popular and more widespread.
You still see this know when you delve into systems and applications
headers which are often a mess of '#ifdef' blocks which special-case
specific compiler versions which all have different characteristics.
On 07/04/2025 20:31, bart wrote:
On 07/04/2025 19:02, Michael S wrote:
On Mon, 07 Apr 2025 05:45:19 -0700
Of course, proposals for similar feature in other procedural/imperative
language would not be totally different. Pascal is more similar to C
than many other procedural languages, so solution for Pascal would
likely be more similar to C than for example, stackless co-routines
that already exist in such languages like C# (that started current wave
of popularity of the feature) or Python.
However Pascal and C have enough not in common for significant
difference in proposed syntax and implementation. Specifically, in
Pascal:
- heap management is built-n in the language
- non-local goto is built-n in the language
That's news to me. But then I only used an educational version.
- nested procedures
- everything related to separated compilation of the translation units
is handwaved in the docs rather than strictly specified.
I don't think it's that strictly specified in C. Isn't it vaguely left
to the implementation?
No.
Much of how different units share macros, types, structs and enums
isn't part of the language at all AFAICS: it's just a by-product of
different modules happening to include the same header files.
Linkage is explained in 6.2.2 - only identifiers with external linkage
are shared amongst translation units. Macros, types, enums are all have
no linkage and are therefore never shared.
The only way to make new non-standard types in C is with "struct",
"union" or "enum". Section 6.2.7 of the standard sets out simply and clearly what is required for two types in different translation units to
be compatible. (It doesn't make sense to say they are the "same type"
in C lingo, since types have no linkage, but compatibility is the
important point.)
Sharing a definition in a header file is normally the easiest way to
ensure that the types used in different translation files are
compatible, but it is not required.
But it could also be done by repeating declarations in each module;
it's rather ad hoc.
It is not remotely "ad hoc" - as far as the language is concerned,
including a header file /is/ repeating the declaration in the different translation units.
The way C handles this kind of thing is arguably
weaker than in languages that have proper modules (like Ada, or Modula
2), and much more open to mistakes. On the other hand, it is very
flexible and simple to understand,
specialised object files or "interface" files. It is possible to write
C code in an "ad hoc" manner (such as declaring an "extern" identifier
within a C file rather than a header file), but the language definition
is not "ad hoc".
On 08/04/2025 09:12, David Brown wrote:
On 07/04/2025 20:31, bart wrote:
On 07/04/2025 19:02, Michael S wrote:
On Mon, 07 Apr 2025 05:45:19 -0700
Of course, proposals for similar feature in other procedural/imperative >>>> language would not be totally different. Pascal is more similar to C
than many other procedural languages, so solution for Pascal would
likely be more similar to C than for example, stackless co-routines
that already exist in such languages like C# (that started current wave >>>> of popularity of the feature) or Python.
However Pascal and C have enough not in common for significant
difference in proposed syntax and implementation. Specifically, in
Pascal:
- heap management is built-n in the language
- non-local goto is built-n in the language
That's news to me. But then I only used an educational version.
- nested procedures
- everything related to separated compilation of the translation units >>>> is handwaved in the docs rather than strictly specified.
I don't think it's that strictly specified in C. Isn't it vaguely
left to the implementation?
No.
C simply has the requirement for separate compilation of modules. Where
does it specify how the implementation does that?
Much of how different units share macros, types, structs and enums
isn't part of the language at all AFAICS: it's just a by-product of
different modules happening to include the same header files.
Linkage is explained in 6.2.2 - only identifiers with external linkage
are shared amongst translation units. Macros, types, enums are all
have no linkage and are therefore never shared.
From the programmer point of view, they are shared. But the language provides no specific mechanism for that.
The only way to make new non-standard types in C is with "struct",
"union" or "enum". Section 6.2.7 of the standard sets out simply and
clearly what is required for two types in different translation units
to be compatible. (It doesn't make sense to say they are the "same
type" in C lingo, since types have no linkage, but compatibility is
the important point.)
Sharing a definition in a header file is normally the easiest way to
ensure that the types used in different translation files are
compatible, but it is not required.
But it could also be done by repeating declarations in each module;
it's rather ad hoc.
It is not remotely "ad hoc" - as far as the language is concerned,
including a header file /is/ repeating the declaration in the
different translation units.
The programmer can achieve the objective in multiple ways; that's what's
ad hoc.
The implementation itself works by crossing its fingers and
hoping that the multiple declarations of the common entity X that are
seen by the different translation unit are fully compatible.
But this need not be the case. For example this is module A:
--------------------------
 #include <stdio.h>
 typedef struct point {float a; float b;} Point;
 float dist(Point);
 int main(void) {
     Point p = {3, 4};
     printf("%f\n", dist(p));
 }
--------------------------
And this is module B that defines 'dist':
--------------------------
 #include <math.h>
 typedef float length;
 typedef struct _tag {length x, y;} vector;
 length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);} --------------------------
The types involved are somewhat different, but are compatible enough for
it to work.
However, they could also be different enough (in a more elaborate
example) for things to superficially work.
This is what I mean by 'ad hoc'.
The way C handles this kind of thing is arguably weaker than in
languages that have proper modules (like Ada, or Modula 2), and much
more open to mistakes. On the other hand, it is very flexible and
simple to understand,
The preprocessor mechanisms available to work with source code are
fairly easy to grasp (but may be complex in practice with multiple
nested headers spread over a file system).
But I had, and do still have, difficulty with how exactly you import and export entities, even ones with linkage.
How compilers deal with it have changed.
But right now, if I put this in
a header shared by A and B modules:
 int abc;
I get 'multiple definition' of abc (from some compilers; others have no problem).
If I stick 'extern' in front, I get 'undefined reference' of abc. To
make it work, 'extern int abc' is shared, and one module must see 'int
abc'.
However if I need to initialise the variable:
  extern int table[];         // shared
  int table[] = (10, 20, 30)
then other modules can't pick up length of the array.
 and does not need additional
specialised object files or "interface" files. It is possible to
write C code in an "ad hoc" manner (such as declaring an "extern"
identifier within a C file rather than a header file), but the
language definition is not "ad hoc".
So, what are the rules again for mixing 'extern' and 'static'
declarations? Since this passes gcc:
 static int def;
 static int def;
 extern int def;
 static int def;
but this doesn't:
 extern int def;
 static int def;
 static int def;
 static int def;
Are you sure they aren't ad hoc? Simply saying that the C standard
enumerates the legal combinations doesn't make them not so!
On 08/04/2025 13:35, bart wrote:
But this need not be the case. For example this is module A:
--------------------------
  #include <stdio.h>
  typedef struct point {float a; float b;} Point;
  float dist(Point);
  int main(void) {
      Point p = {3, 4};
      printf("%f\n", dist(p));
  }
--------------------------
And this is module B that defines 'dist':
--------------------------
  #include <math.h>
  typedef float length;
  typedef struct _tag {length x, y;} vector;
  length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
--------------------------
The types involved are somewhat different, but are compatible enough
for it to work.
The two types are entirely compatible.
"typedef" does not introduce a
new type, and struct types in different modules are compatible if they
are build from the same compatible field types in the same order.
However, they could also be different enough (in a more elaborate
example) for things to superficially work.
Not in C.
The preprocessor mechanisms available to work with source code are
fairly easy to grasp (but may be complex in practice with multiple
nested headers spread over a file system).
That's like complaining that integer addition is complex because someone might want to add 26 digit numbers. Stop being silly.
But I had, and do still have, difficulty with how exactly you import
and export entities, even ones with linkage.
That sounds very much like a "Bart" problem.
 If you /genuinely/ want to
know, and you can't figure it out with a quick google search, reading
the page in the standards, or looking at an introduction to C book, then please ask. If you are just trying to claim opportunities to say it's
all so difficult and confusing, then don't bother.
How compilers deal with it have changed.
As a general rule, they have not.
But it is true that some compilers have by default supported an
extension that was designed to make interoperability with Fortran
programs easier
However if I need to initialise the variable:
   extern int table[];         // shared
   int table[] = (10, 20, 30)
then other modules can't pick up length of the array.
Correct.
The C standard gives clear rules here that make sense.
mean they are the /only/ set of rules a language could have that makes
sense, but they are not "ad hoc". That would imply that combinations
like this could have unpredictable meanings.
On 08/04/2025 15:50, David Brown wrote:
On 08/04/2025 13:35, bart wrote:
But this need not be the case. For example this is module A:
--------------------------
#include <stdio.h>
typedef struct point {float a; float b;} Point;
float dist(Point);
int main(void) {
Point p = {3, 4};
printf("%f\n", dist(p));
}
--------------------------
And this is module B that defines 'dist':
--------------------------
#include <math.h>
typedef float length;
typedef struct _tag {length x, y;} vector;
length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
--------------------------
The types involved are somewhat different, but are compatible
enough for it to work.
The two types are entirely compatible.
Are they?
On 08/04/2025 09:12, David Brown wrote:[discussing Pascal]
On 07/04/2025 20:31, bart wrote:
On 07/04/2025 19:02, Michael S wrote:
On Mon, 07 Apr 2025 05:45:19 -0700
- nested procedures
- everything related to separated compilation of the translation
units is handwaved in the docs rather than strictly specified.
I don't think it's that strictly specified in C. Isn't it vaguely
left to the implementation?
No.
C simply has the requirement for separate compilation of
modules. Where does it specify how the implementation does that?
On Mon, 07 Apr 2025 05:45:19 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 06 Apr 2025 07:32:16 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 06 Apr 2025 05:47:47 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Furthermore, even if there had been a posting that concerns
only a gcc extension and nothing else, and is one I didn't
respond to, that doesn't excuse your action. It isn't like
this is the first time you have posted something here that
is not about C but only about your fantasy language, and
also not the first time the unsuitability of such postings
has been pointed out. You're a repeat offender. So stop
pretending you are being picked on for no reason.
Could you recommend a more appropriate place for Thiago and others
where they can discuss C-like fantasy languages?
The newsgroup comp.lang.misc seems like a natural candidate.
I don't know if comp.lang.misc has an official charter, but at
least to me new features of any widely used programming language
would appear to fall under the umbrella of comp.lang.misc.
My question was not completely abstract.
I did consider starting a discussion about possibility of inclusion
of stackless co-routines into one of the future editions of C.
Naturally, my ideas at this state are extremely in-concrete, much
more so then the post of Thiago Adams that started this thread.
So, if I ever come to it, which by itself is not very likely, do you
think that comp.lang.misc would be better place than comp.lang.c ?
Before giving an answer I would like to ask some questions.
* How much does the (still fuzzy) idea depend on running in a C
environment? Is it very specific to C, or might it be applicable
to other procedural/imperative languages (for example, Pascal)?
* How much does the current C language impact what you expect to
propose? Which aspects of C need to be taken into consideration
in forming the proposal, and how strongly do those considerations
affect the specifics of what would be proposed?
* Assuming you get to a point where you are happy with the details
of a proposed extension, how likely is it that you would write a
proposal for the C standard committee, and make the effort needed
to shepherd it through the process of being accepted for a future
C standard?
Not likely. I would have to somehow convince somebody else to do it.
bart <bc@freeuk.com> writes:
On 08/04/2025 15:50, David Brown wrote:
On 08/04/2025 13:35, bart wrote:
But this need not be the case. For example this is module A:
--------------------------
#include <stdio.h>
typedef struct point {float a; float b;} Point;
float dist(Point);
int main(void) {
Point p = {3, 4};
printf("%f\n", dist(p));
}
--------------------------
And this is module B that defines 'dist':
--------------------------
#include <math.h>
typedef float length;
typedef struct _tag {length x, y;} vector;
length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
--------------------------
The types involved are somewhat different, but are compatible
enough for it to work.
The two types are entirely compatible.
Are they?
No, they are not. The type names 'Point' and 'vector' name two
distinct types, and those types are not compatible, because
the two struct tags are different.
Because the two types are not compatible, even just calling the
function dist() is undefined behavior.
On 2025-04-04, Kaz Kylheku <643-408-1753@kylheku.com> wrote:
On 2025-04-04, Thiago Adams <thiago.adams@gmail.com> wrote:
What do you think of this control block?
do
{
FILE f = fopen("file.txt", "r");
if (f == NULL) quit; /*goes to else part*/
/*success here*/
for (int i =0; i < 10; i++){
...
if (error) quit;
}
}
else
{
/*some error*/
}
The else part might need access to some local variables
in the main part.
do {
char *name = calculate_path(PATH_PREFIX "/", name, ".txt");
FILE *f = fopen(...)
if (!f)
quit;
...
}
else
{
printf("unable to open %s\n", name);
...
}
If you make that work, you're creating scope wormholes between
disjoint curly braces, which is not allowed if youre name isn't
Bjarne Stroustrup.
How about: do/else if/else if/else with argument passing to first
clause whose signature can take the argument list:
do {
...
quit("rage"); // goes to (char *arg)
...
quit(42); // goes to (int arg)
...
}
else if (char *arg) // or just else? multiple elses on do, why not.
{
}
else (int arg)
{
}
Friday `f`noons, eh?
On 08/04/2025 18:32, Tim Rentsch wrote:
bart <bc@freeuk.com> writes:
On 08/04/2025 15:50, David Brown wrote:
On 08/04/2025 13:35, bart wrote:
But this need not be the case. For example this is module A:
--------------------------
#include <stdio.h>
typedef struct point {float a; float b;} Point;
float dist(Point);
int main(void) {
Point p = {3, 4};
printf("%f\n", dist(p));
}
--------------------------
And this is module B that defines 'dist':
--------------------------
#include <math.h>
typedef float length;
typedef struct _tag {length x, y;} vector;
length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
--------------------------
The types involved are somewhat different, but are compatible
enough for it to work.
The two types are entirely compatible.
Are they?
No, they are not. The type names 'Point' and 'vector' name two
distinct types, and those types are not compatible, because
the two struct tags are different.
Because the two types are not compatible, even just calling the
function dist() is undefined behavior.
I get an incompatible error (from the example you snipped) even when I
remove both struct tags.
I can't use the same struct tag in the same scope as one will clash
with the other. But if I have the second in an inner scope, then I
again get the error.
bart <bc@freeuk.com> writes:
On 08/04/2025 18:32, Tim Rentsch wrote:
bart <bc@freeuk.com> writes:
On 08/04/2025 15:50, David Brown wrote:
On 08/04/2025 13:35, bart wrote:
But this need not be the case. For example this is module A:
--------------------------
#include <stdio.h>
typedef struct point {float a; float b;} Point;
float dist(Point);
int main(void) {
Point p = {3, 4};
printf("%f\n", dist(p));
}
--------------------------
And this is module B that defines 'dist':
--------------------------
#include <math.h>
typedef float length;
typedef struct _tag {length x, y;} vector;
length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
--------------------------
The types involved are somewhat different, but are compatible
enough for it to work.
The two types are entirely compatible.
Are they?
No, they are not. The type names 'Point' and 'vector' name two
distinct types, and those types are not compatible, because
the two struct tags are different.
Because the two types are not compatible, even just calling the
function dist() is undefined behavior.
I get an incompatible error (from the example you snipped) even when I
remove both struct tags.
I can't use the same struct tag in the same scope as one will clash
with the other. But if I have the second in an inner scope, then I
again get the error.
If you want to make a point or ask a question about C code,
SHOW THE CODE. And show all of it. Don't make people guess
by showing only some of the code or by giving just a description.
On 08/04/2025 22:18, Tim Rentsch wrote:
bart <bc@freeuk.com> writes:
On 08/04/2025 18:32, Tim Rentsch wrote:
bart <bc@freeuk.com> writes:
On 08/04/2025 15:50, David Brown wrote:
On 08/04/2025 13:35, bart wrote:
But this need not be the case. For example this is module A:
--------------------------
#include <stdio.h>
typedef struct point {float a; float b;} Point;
float dist(Point);
int main(void) {
Point p = {3, 4};
printf("%f\n", dist(p));
}
--------------------------
And this is module B that defines 'dist':
--------------------------
#include <math.h>
typedef float length;
typedef struct _tag {length x, y;} vector;
length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
--------------------------
The types involved are somewhat different, but are compatible
enough for it to work.
The two types are entirely compatible.
Are they?
No, they are not. The type names 'Point' and 'vector' name two
distinct types, and those types are not compatible, because
the two struct tags are different.
Because the two types are not compatible, even just calling the
function dist() is undefined behavior.
I get an incompatible error (from the example you snipped) even when I
remove both struct tags.
I can't use the same struct tag in the same scope as one will clash
with the other. But if I have the second in an inner scope, then I
again get the error.
If you want to make a point or ask a question about C code,
SHOW THE CODE. And show all of it. Don't make people guess
by showing only some of the code or by giving just a description.
I'm showing the code but you keep snipping it! [...]
I get an incompatible error (from the example you snipped) even when I
remove both struct tags.
I can't use the same struct tag in the same scope as one will clash
with the other. But if I have the second in an inner scope, then I
again get the error.
bart <bc@freeuk.com> writes:
If you want to make a point or ask a question about C code,
SHOW THE CODE. And show all of it. Don't make people guess
by showing only some of the code or by giving just a description.
I'm showing the code but you keep snipping it! [...]
No, I don't. Don't be so obtuse. I included the code I was
originally commenting on, in my first followup. My comment about
showing code was about your second posting. Let me repeat the two
important paragraphs (quoted above) taken from that posting:
I get an incompatible error (from the example you snipped) even when I >>>> remove both struct tags.
The phrase "even when I remove both struct tags" describes code, it
doesn't show the code.
Two typedefs for same struct layout appear to create distinct types;
this fails:
typedef struct {float x, y;} Point;
typedef struct {float x, y;} vector;
Point p;
vector v;
p=v;
I can't use the same struct tag in the same scope as one will clash with
the other.
But if I have the second in an inner scope, then I again get
the error.
Michael S <already5chosen@yahoo.com> writes:
On Mon, 07 Apr 2025 05:45:19 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 06 Apr 2025 07:32:16 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 06 Apr 2025 05:47:47 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Furthermore, even if there had been a posting that concerns
only a gcc extension and nothing else, and is one I didn't
respond to, that doesn't excuse your action. It isn't like
this is the first time you have posted something here that
is not about C but only about your fantasy language, and
also not the first time the unsuitability of such postings
has been pointed out. You're a repeat offender. So stop
pretending you are being picked on for no reason.
Could you recommend a more appropriate place for Thiago and
others where they can discuss C-like fantasy languages?
The newsgroup comp.lang.misc seems like a natural candidate.
I don't know if comp.lang.misc has an official charter, but at
least to me new features of any widely used programming language
would appear to fall under the umbrella of comp.lang.misc.
My question was not completely abstract.
I did consider starting a discussion about possibility of
inclusion of stackless co-routines into one of the future
editions of C. Naturally, my ideas at this state are extremely
in-concrete, much more so then the post of Thiago Adams that
started this thread. So, if I ever come to it, which by itself is
not very likely, do you think that comp.lang.misc would be better
place than comp.lang.c ?
Before giving an answer I would like to ask some questions.
* How much does the (still fuzzy) idea depend on running in a C
environment? Is it very specific to C, or might it be applicable
to other procedural/imperative languages (for example, Pascal)?
* How much does the current C language impact what you expect to
propose? Which aspects of C need to be taken into consideration
in forming the proposal, and how strongly do those considerations
affect the specifics of what would be proposed?
[...]
My apologies; I gave the wrong impression. I didn't mean I wanted
to see the answers myself. What I did mean is that the questions
are good for you (or someone else) to ask of themselves
to decide
whether comp.lang.c or comp.lang.misc (or possibly some other group)
is a better place for a posting.
Given that the details seem to be still a bit fuzzy, I tend to think comp.lang.misc is a better place to start. But after thinking about
the questions you might decide otherwise.
* Assuming you get to a point where you are happy with the details
of a proposed extension, how likely is it that you would write a
proposal for the C standard committee, and make the effort needed
to shepherd it through the process of being accepted for a future
C standard?
Not likely. I would have to somehow convince somebody else to do
it.
I see. Well, good luck with that. :)
However if I need to initialise the variable:
extern int table[]; // shared
int table[] = (10, 20, 30)
then other modules can't pick up length of the array.
In C, if you declare two structs in the same translation unit with
the same field types and the same field names, they are still
different types.
This applies to all languages. For example, in Python you do not
have separate "interface" and "implementation" files - everything is
in one ".py" file. If I have a Python module that says "import
my_py_lib", how does Python know where to find "my_py_lib.py" ? How
does it know which copy of "my_py_lib.py" to use from the dozen that
I have on my computer? The answer is it uses some default rules for
the language, some default rules for the implementation, some
configuration settings, some flags, some run-time information
(equivalent to compile-time information in compiled languages). The
exact details are different, but the principle is the same for C and
for any other language that can handle more than one file.
On 08/04/2025 15:50, David Brown wrote:
On 08/04/2025 13:35, bart wrote:
But this need not be the case. For example this is module A:
--------------------------
  #include <stdio.h>
  typedef struct point {float a; float b;} Point;
  float dist(Point);
  int main(void) {
      Point p = {3, 4};
      printf("%f\n", dist(p));
  }
--------------------------
And this is module B that defines 'dist':
--------------------------
  #include <math.h>
  typedef float length;
  typedef struct _tag {length x, y;} vector;
  length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
--------------------------
The types involved are somewhat different, but are compatible enough
for it to work.
The two types are entirely compatible.
Are they?
So why does gcc report an error here (the two types are from
my example):
 typedef struct point {float a; float b;} Point;
 typedef float length;
 typedef struct _tag {length x, y;} vector;
 Point p;
 vector v;
 p=v;
c.c:14:5: error: incompatible types when assigning to type 'Point' {aka 'struct point'} from type
ector' {aka 'struct _tag'}
  14 |  p=v;
     |    ^
"typedef" does not introduce a new type, and struct types in different
modules are compatible if they are build from the same compatible
field types in the same order.
However, they could also be different enough (in a more elaborate
example) for things to superficially work.
Not in C.
Really? I could have added a dozen extra fields to one (or a pile of incompatible fields to both), and it can still work (especially if I
pass the struct by reference).
The preprocessor mechanisms available to work with source code are
fairly easy to grasp (but may be complex in practice with multiple
nested headers spread over a file system).
That's like complaining that integer addition is complex because
someone might want to add 26 digit numbers. Stop being silly.
You're missing the point: the concept may be simple, but as typically
used in C, it is can be much more complex than necessary.
Doing:
 #include "lib.h"
is not enough; there may be a dozen different header locations (from
nested includes) that need to be made known to the compiler, so you need
to figure them out first!
A program may comprise 100 .c files, but use 37 different headers in
mixed, possible nested combinations across those 100 modules. You can't
in general tie one .c file to a specific .h file; /that/ would be simpler.
So the usual thing applies in C: the language lays down some vague
rules, beyond that it's a free-for-all.
You choose to call that 'being flexible'; I might call it something else.
But I had, and do still have, difficulty with how exactly you import
and export entities, even ones with linkage.
That sounds very much like a "Bart" problem.
You really think that I wouldn't know how to do this if the language
provided genuinely simple and well-thought-out and consistent rules?
 If you /genuinely/ want to know, and you can't figure it out with a
quick google search, reading the page in the standards, or looking at
an introduction to C book, then please ask. If you are just trying to
claim opportunities to say it's all so difficult and confusing, then
don't bother.
Ah yes, the Microsoft approach: provide huge amounts of resources,
manuals, training courses etc, rather than making something actually
simple!
How compilers deal with it have changed.
As a general rule, they have not.
But it is true that some compilers have by default supported an
extension that was designed to make interoperability with Fortran
programs easier
Which means a pile of badly written programs.
However if I need to initialise the variable:
   extern int table[];         // shared
   int table[] = (10, 20, 30)
then other modules can't pick up length of the array.
Correct.
And the workaround is...?
(Maybe you can appreciate one of many reasons why I normally generate C
code for a project as one source file.)
The C standard gives clear rules here that make sense.
What's the rational for allowing both static and extern versions of the
same entity in the same file? And if that is allowed, why does the order matter?
(In my compiler I gave up trying to make sense of it, and just ended up
allow any combination unless it was clearly wrong.)
 That does not
mean they are the /only/ set of rules a language could have that makes
sense, but they are not "ad hoc". That would imply that combinations
like this could have unpredictable meanings.
I don't mean 'ad hoc' to be 'indeterminate'. More like, 'mess', or 'free-for-all'.
On 08/04/2025 18:28, bart wrote:
On 08/04/2025 15:50, David Brown wrote:
On 08/04/2025 13:35, bart wrote:
But it is true that some compilers have by default supported an
extension that was designed to make interoperability with Fortran
programs easier
Which means a pile of badly written programs.
That is why I said it was a bad idea for gcc to have "-fcommon" as
the default. It is a real shame that it took so long to change it.
However, while that default meant that some people wrote C code with
a misunderstanding of linkages and the difference between
declarations and definitions, most C programmers don't make that
mistake. When gcc eventually changed the default, it did not lead to wide-spread breakage of code.
On 08/04/2025 18:28, bart wrote:
On 08/04/2025 15:50, David Brown wrote:
The two types are entirely compatible.
Are they?
Yes.
So why does gcc report an error here (the two types are from my example):
  typedef struct point {float a; float b;} Point;
  typedef float length;
  typedef struct _tag {length x, y;} vector;
  Point p;
  vector v;
  p=v;
c.c:14:5: error: incompatible types when assigning to type
'Point' {aka 'struct point'} from type
ector' {aka 'struct _tag'}
   14 |  p=v;
      |    ^
That is a different situation. In the first case, the types were
defined in different translation units - and are compatible. In the
second case, they are within the same translation unit, and are not compatible.
In C, if you declare two structs in the same translation unit with the
same field types and the same field names, they are still different
types. That is important for making new types - it is how you get
strong typing in C (albeit with less user convenience than in some other languages). It means that you can't mix up two types just because of coincidences in the fields.
This means that when you have a struct declaration in two translation
units (locally in the C file, or via a header file - there is no distinction), they form two different types as they are separate declarations. If C did not specify that these were compatible, it would
be impossible (without UB) to use struct or union types across
translation units.
You are still wrong.
On 2025-04-08, bart <bc@freeuk.com> wrote:
However if I need to initialise the variable:
extern int table[]; // shared
int table[] = (10, 20, 30)
then other modules can't pick up length of the array.
extern int table[3];
On 08/04/2025 18:28, bart wrote:
[...]
I believe the meaning of "extern" in combination with other
storage-class specifiers was picked to work with existing old code from before "extern" was added to the language.
On 09.04.2025 11:42, David Brown wrote:
On 08/04/2025 18:28, bart wrote:
[...]
I believe the meaning of "extern" in combination with other
storage-class specifiers was picked to work with existing old code
from before "extern" was added to the language.
Assuming you mean the "C" language I don't quite understand the last
part of the sentence. Wasn't 'extern' already in "K&R" - so what was
"the language" before the addition of 'extern'?
Or did you just mean to say "[...] before _combinations_ of 'extern'
and other storage-class specifier were added to the language."
Janis, puzzled
On 08/04/2025 18:32, Tim Rentsch wrote:
bart <bc@freeuk.com> writes:
On 08/04/2025 15:50, David Brown wrote:
On 08/04/2025 13:35, bart wrote:
But this need not be the case. For example this is module A:
--------------------------
 #include <stdio.h>
 typedef struct point {float a; float b;} Point;
 float dist(Point);
 int main(void) {
 Point p = {3, 4};
 printf("%f\n", dist(p));
 }
--------------------------
And this is module B that defines 'dist':
--------------------------
 #include <math.h>
 typedef float length;
 typedef struct _tag {length x, y;} vector;
 length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
--------------------------
The types involved are somewhat different, but are compatible
enough for it to work.
The two types are entirely compatible.
Are they?
No, they are not. The type names 'Point' and 'vector' name two
distinct types, and those types are not compatible, because
the two struct tags are different.
Because the two types are not compatible, even just calling the
function dist() is undefined behavior.
I get an incompatible error (from the example you snipped) even when I
remove both struct tags.
I can't use the same struct tag in the same scope as one will clash with
the other. But if I have the second in an inner scope, then I again get
the error.
It doesn't seem to be anything to do with struct tags.
Two typedefs for same struct layout appear to create distinct types;
this fails:
 typedef struct {float x, y;} Point;
 typedef struct {float x, y;} vector;
 Point p;
 vector v;
 p=v;
But this works:
 typedef struct {float x, y;} Point, vector;
 Point p;
 vector v;
 p=v;
So it seems to depend on whether Point and vector share the same
internal descriptor for the struct.
In my original example, the structs were defined in separate translation unit, so the compiler has to take things on trust.
On Wed, 9 Apr 2025 11:42:36 +0200
David Brown <david.brown@hesbynett.no> wrote:
In C, if you declare two structs in the same translation unit with
the same field types and the same field names, they are still
different types.
That is clear for structs with tags. Less clear for tagless structs
that have exactly the same fields.
On 08/04/2025 18:32, Tim Rentsch wrote:
bart <bc@freeuk.com> writes:
On 08/04/2025 15:50, David Brown wrote:
On 08/04/2025 13:35, bart wrote:
But this need not be the case. For example this is module A:
--------------------------
 #include <stdio.h>
 typedef struct point {float a; float b;} Point;
 float dist(Point);
 int main(void) {
 Point p = {3, 4};
 printf("%f\n", dist(p));
 }
--------------------------
And this is module B that defines 'dist':
--------------------------
 #include <math.h>
 typedef float length;
 typedef struct _tag {length x, y;} vector;
 length dist(vector p) {return sqrt(p.x*p.x + p.y*p.y);}
--------------------------
The types involved are somewhat different, but are compatible
enough for it to work.
The two types are entirely compatible.
Are they?
No, they are not. The type names 'Point' and 'vector' name two
distinct types, and those types are not compatible, because
the two struct tags are different.
Because the two types are not compatible, even just calling the
function dist() is undefined behavior.
I get an incompatible error (from the example you snipped) even when I
remove both struct tags.
I can't use the same struct tag in the same scope as one will clash with
the other.
But if I have the second in an inner scope, then I again get
the error.
It doesn't seem to be anything to do with struct tags.
Two typedefs for same struct layout appear to create distinct types;
this fails:
 typedef struct {float x, y;} Point;
 typedef struct {float x, y;} vector;
 Point p;
 vector v;
 p=v;
But this works:
 typedef struct {float x, y;} Point, vector;
 Point p;
 vector v;
 p=v;
So it seems to depend on whether Point and vector share the same
internal descriptor for the struct.
In my original example, the structs were defined in separate translation unit, so the compiler has to take things on trust.
On Wed, 9 Apr 2025 11:42:36 +0200
David Brown <david.brown@hesbynett.no> wrote:
This applies to all languages. For example, in Python you do not
have separate "interface" and "implementation" files - everything is
in one ".py" file. If I have a Python module that says "import
my_py_lib", how does Python know where to find "my_py_lib.py" ? How
does it know which copy of "my_py_lib.py" to use from the dozen that
I have on my computer? The answer is it uses some default rules for
the language, some default rules for the implementation, some
configuration settings, some flags, some run-time information
(equivalent to compile-time information in compiled languages). The
exact details are different, but the principle is the same for C and
for any other language that can handle more than one file.
It is not quite the same for all languages. The degree in which it is standardizes vs left to implementation differs. In some languages it is
fully standardized.
I think, in case of Ada it was standardized in APSE. But then, real
world mostly accepted a language part of Ada standard and mostly
ignored APSE part.
On 09/04/2025 10:42, David Brown wrote:
On 08/04/2025 18:28, bart wrote:
On 08/04/2025 15:50, David Brown wrote:
The two types are entirely compatible.
Are they?
Yes.
So why does gcc report an error here (the two types are from my
example):
  typedef struct point {float a; float b;} Point;
  typedef float length;
  typedef struct _tag {length x, y;} vector;
  Point p;
  vector v;
  p=v;
c.c:14:5: error: incompatible types when assigning to type 'Point'
{aka 'struct point'} from type
ector' {aka 'struct _tag'}
   14 |  p=v;
      |    ^
That is a different situation. In the first case, the types were
defined in different translation units - and are compatible. In the
second case, they are within the same translation unit, and are not
compatible.
This doesn't make sense at all.
Turning it around, you're saying that if T an U are incompatible types
within the same translation unit, they suddenly become compatible if
split across two translation units?
In C, if you declare two structs in the same translation unit with the
same field types and the same field names, they are still different
types. That is important for making new types - it is how you get
strong typing in C (albeit with less user convenience than in some
other languages). It means that you can't mix up two types just
because of coincidences in the fields.
This means that when you have a struct declaration in two translation
units (locally in the C file, or via a header file - there is no
distinction), they form two different types as they are separate
declarations. If C did not specify that these were compatible, it
would be impossible (without UB) to use struct or union types across
translation units.
So, yes, you are saying that. In short, if a programmer says that incompatible types T and U are the same (where the compiler can only see
T in module A and U in module B), then the programmer must be trusted,
even though they would be wrong.
Note that I, as the programmer, said this:
"The types involved are somewhat different, but are compatible enough
for it to work."
What you are saying is that even though I was actually telling the
truth, I was wrong. But I would be right if I lied about it....
We're either through the Looking-Glass at this point, or somewhere not
in Kansas!
I'll have to think about this before replying to any other points.
You are still wrong.
Never mind. I've just spotted this at the end. In that case, and given
what you said above where you arguing that Black is White, discussion is futile.
On 2025-04-08, bart <bc@freeuk.com> wrote:
However if I need to initialise the variable:
extern int table[]; // shared
int table[] = (10, 20, 30)
then other modules can't pick up length of the array.
extern int table[3];
On Wed, 9 Apr 2025 11:42:36 +0200
David Brown <david.brown@hesbynett.no> wrote:
On 08/04/2025 18:28, bart wrote:
On 08/04/2025 15:50, David Brown wrote:
On 08/04/2025 13:35, bart wrote:
But it is true that some compilers have by default supported an
extension that was designed to make interoperability with Fortran
programs easier
Which means a pile of badly written programs.
That is why I said it was a bad idea for gcc to have "-fcommon" as
the default. It is a real shame that it took so long to change it.
However, while that default meant that some people wrote C code with
a misunderstanding of linkages and the difference between
declarations and definitions, most C programmers don't make that
mistake. When gcc eventually changed the default, it did not lead to
wide-spread breakage of code.
I wouldn't be so sure.
I have no statistics, but would expect that very significant part of Unix-only C programmers, especially grumpy old timers, believes that '-fcommon' is the real C and the rest are heresies.
On 09/04/2025 12:51, bart wrote:
On 09/04/2025 10:42, David Brown wrote:
On 08/04/2025 18:28, bart wrote:
On 08/04/2025 15:50, David Brown wrote:
The two types are entirely compatible.
Are they?
Yes.
So why does gcc report an error here (the two types are from my
example):
  typedef struct point {float a; float b;} Point;
  typedef float length;
  typedef struct _tag {length x, y;} vector;
  Point p;
  vector v;
  p=v;
c.c:14:5: error: incompatible types when assigning to type
'Point' {aka 'struct point'} from type
ector' {aka 'struct _tag'}
   14 |  p=v;
      |    ^
That is a different situation. In the first case, the types were
defined in different translation units - and are compatible. In the
second case, they are within the same translation unit, and are not
compatible.
This doesn't make sense at all.
Turning it around, you're saying that if T an U are incompatible types
within the same translation unit, they suddenly become compatible if
split across two translation units?
In the specific case of structs and unions matching the requirements in 6.2.7, yes. /Please/ read that section of the standard before making
any more posts about it.
There are plenty of differences between compiling two C files
independently, and pasting them directly together in one file and
compiling that. This is one of those differences.
In C, if you declare two structs in the same translation unit with
the same field types and the same field names, they are still
different types. That is important for making new types - it is how
you get strong typing in C (albeit with less user convenience than in
some other languages). It means that you can't mix up two types just
because of coincidences in the fields.
This means that when you have a struct declaration in two translation
units (locally in the C file, or via a header file - there is no
distinction), they form two different types as they are separate
declarations. If C did not specify that these were compatible, it
would be impossible (without UB) to use struct or union types across
translation units.
So, yes, you are saying that. In short, if a programmer says that
incompatible types T and U are the same (where the compiler can only
see T in module A and U in module B), then the programmer must be
trusted, even though they would be wrong.
Yes.
Note that I, as the programmer, said this:
"The types involved are somewhat different, but are compatible enough
for it to work."
It's not quite like that - C says that although they are different types (since they are in different translation units), they are compatible in
this situation. Not "compatible enough to work", but /actually/
compatible in the specific C technical sense. (Section 6.2.7 has "compatible type" in italics - it defines what is meant by that term in
the C language.)
What you are saying is that even though I was actually telling the
truth, I was wrong. But I would be right if I lied about it....
No, you were not telling the truth - you were wildly mixing things.
We're either through the Looking-Glass at this point, or somewhere not
in Kansas!
I'll have to think about this before replying to any other points.
Marvellous - I'd appreciate you putting more thought into this, and less knee-jerk reactions and exaggerations. Please also read the relevant
parts of the standards before replying - at the very least, section
6.2.7p1 and section 6.2.2. Once you have read these and tried to
understand them, it will be a lot easier to clear up any remaining issues.
On 09/04/2025 13:36, David Brown wrote:
On 09/04/2025 12:51, bart wrote:
I'll have to think about this before replying to any other points.
Marvellous - I'd appreciate you putting more thought into this, and
less knee-jerk reactions and exaggerations. Please also read the
relevant parts of the standards before replying - at the very least,
section 6.2.7p1 and section 6.2.2. Once you have read these and tried
to understand them, it will be a lot easier to clear up any remaining
issues.
I'm not going to wade through reams of Standard minutiae, sorry.
Are T and U compatible types are not? The answer must be unequivocal
without needing to be a 'standards-head'.
This has been said in this
thread:
BC: The types involved are somewhat different, but are compatible enough
   for it to work. [In that the member types, offsets and overall size,
   since pass-by-value is used, correspond]
DB: The two types are entirely compatible.
BC: Are they?
TR: No, they are not.
You say they're compatible, Tim Rentsch says they're not; who's right?
The original point I'd been making was that, in C, there is no dedicated mechansism for sharing user-defined named entities like types, across modules.
I notice you ignored the example in my language, many posts back, which
makes it impossible to make such a mistake.
On 09/04/2025 15:13, bart wrote:
On 09/04/2025 13:36, David Brown wrote:
On 09/04/2025 12:51, bart wrote:
I'll have to think about this before replying to any other points.
Marvellous - I'd appreciate you putting more thought into this, and
less knee-jerk reactions and exaggerations. Please also read the
relevant parts of the standards before replying - at the very least,
section 6.2.7p1 and section 6.2.2. Once you have read these and
tried to understand them, it will be a lot easier to clear up any
remaining issues.
I'm not going to wade through reams of Standard minutiae, sorry.
Again, no one is suggesting that you read the entire C standard. After
all, that would clearly be an absurd idea for someone who spends such a
lot of his time arguing about the C language and who even claims to have
made a C compiler.
I have given you clear references to two small parts of the standard. It really is not a lot of effort.
Are T and U compatible types are not? The answer must be unequivocal
without needing to be a 'standards-head'.
I have told you several times, for different variations of that "T" and
"U" mean.
Since you don't believe my explanations, and won't read the standards,
I'm not sure how much more help I can be.
This has been said in this thread:
BC: The types involved are somewhat different, but are compatible enough
    for it to work. [In that the member types, offsets and overall size,
    since pass-by-value is used, correspond]
DB: The two types are entirely compatible.
BC: Are they?
TR: No, they are not.
You say they're compatible, Tim Rentsch says they're not; who's right?
You have moved the goalposts around
so often that it is hard to keep
track. But Tim is correct - the names, when given, have to match as
well as the types of the fields (but a typedef alias giving a different
name to the same type is fine).
The original point I'd been making was that, in C, there is no
dedicated mechansism for sharing user-defined named entities like
types, across modules.
There /is/ a dedicated mechanism - described in 6.2.7p1.
I notice you ignored the example in my language, many posts back,
which makes it impossible to make such a mistake.
Yes, I ignore your examples in your language - they have no bearing or relevance to anyone except you.
 We all know there are other ways for a
language to implement inter-unit sharing of information. We all know
that some of these can reduce the risk of certain errors. We all know
that you have to follow a simple rule in order to negate that risk in C
- put shared types in shared headers.
 No language negates all risks of
errors - whatever language you use, you follow practices that balance
the risk of errors with the convenience or flexibility that you want in
the code.
On Wed, 9 Apr 2025 12:58:08 +0200
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
On 09.04.2025 11:42, David Brown wrote:
On 08/04/2025 18:28, bart wrote:
[...]
I believe the meaning of "extern" in combination with other
storage-class specifiers was picked to work with existing old code
from before "extern" was added to the language.
Assuming you mean the "C" language I don't quite understand the last
part of the sentence. Wasn't 'extern' already in "K&R" - so what was
"the language" before the addition of 'extern'?
Or did you just mean to say "[...] before _combinations_ of 'extern'
and other storage-class specifier were added to the language."
Janis, puzzled
K&R was published in 1978, 5 years after C got its first users.
Back in 1973-74 C language was significantly different from what it
became few years later.
On Tue, 08 Apr 2025 10:59:50 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
My apologies; I gave the wrong impression. I didn't mean I wanted
to see the answers myself. What I did mean is that the questions
are good for you (or someone else) to ask of themselves
Even more interesting question to ask myself is why I want stackless coroutines in C to be different from how they were recently added to
C++ and Rust - two languages that are relatively similar to C in their assumed execution models. Relatively, that is.
to decide
whether comp.lang.c or comp.lang.misc (or possibly some other group)
is a better place for a posting.
I took a look at comp.lang.misc.
It does not appear to have much of the life of its own. Nearly all
threads that lasted for more that 5 messages did so due to crossposts
from other groups.
On 09/04/2025 00:27, Tim Rentsch wrote:
bart <bc@freeuk.com> writes:
If you want to make a point or ask a question about C code,
SHOW THE CODE. And show all of it. Don't make people guess
by showing only some of the code or by giving just a description.
I'm showing the code but you keep snipping it! [...]
No, I don't. Don't be so obtuse. I included the code I was
originally commenting on, in my first followup. My comment about
showing code was about your second posting. Let me repeat the two
important paragraphs (quoted above) taken from that posting:
I get an incompatible error (from the example you snipped) even when I >>>>> remove both struct tags.
The phrase "even when I remove both struct tags" describes code, it
doesn't show the code.
I showed this example a few lines later [in an earlier posting]
which has both struct tags omitted:
bart <bc@freeuk.com> writes:
On 09/04/2025 00:27, Tim Rentsch wrote:
bart <bc@freeuk.com> writes:
If you want to make a point or ask a question about C code,
SHOW THE CODE. And show all of it. Don't make people guess
by showing only some of the code or by giving just a description.
I'm showing the code but you keep snipping it! [...]
No, I don't. Don't be so obtuse. I included the code I was
originally commenting on, in my first followup. My comment about
showing code was about your second posting. Let me repeat the two
important paragraphs (quoted above) taken from that posting:
I get an incompatible error (from the example you snipped) even when I >>>>>> remove both struct tags.
The phrase "even when I remove both struct tags" describes code, it
doesn't show the code.
I showed this example a few lines later [in an earlier posting]
which has both struct tags omitted:
There is a simple lesson that you need to learn:
When someone is responding to a post, they are responding ONLY to
the content in the posting they are responing to; not to some
earlier posting in the same thread, not to a different posting
submitted two weeks ago, not to what you meant to say but didn't,
not to thoughts in your head but that you didn't say, but ONLY TO
WHAT IS SAID IN THE POSTING BEING RESPONDED TO.
If you can learn to follow this simple rule everyone in the
newsgroup will be better off, including you.
I'm not sure what your gripe is other than maybe I picked up on
something you got wrong. The discussion was about two struct types like
this:
typedef struct tag1 {...} T1;
typedef struct tag2 {...} T2;
and whether T1 and T2 were compatible or not. You said:
"and those types are not compatible, because the two struct tags are different."
In this case the tags would be "tag1" and "tag2". I then said:
"I get an incompatible error (from the example you snipped) even when I remove both struct tags."
That means removing "tag1" and "tag2" so the example above looks like this:
typedef struct {...} T1;
typedef struct {...} T2;
Here, you can't say the struct tags are different, as they are not
visible!
As I concluded, your assertion about compatibility being based on tags
being the same or not didn't seem right.)
Michael S <already5chosen@yahoo.com> writes:
On Wed, 9 Apr 2025 12:58:08 +0200
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
On 09.04.2025 11:42, David Brown wrote:
On 08/04/2025 18:28, bart wrote:
[...]
I believe the meaning of "extern" in combination with other
storage-class specifiers was picked to work with existing old
code from before "extern" was added to the language.
Assuming you mean the "C" language I don't quite understand the
last part of the sentence. Wasn't 'extern' already in "K&R" - so
what was "the language" before the addition of 'extern'?
Or did you just mean to say "[...] before _combinations_ of
'extern' and other storage-class specifier were added to the
language."
Janis, puzzled
K&R was published in 1978, 5 years after C got its first users.
Back in 1973-74 C language was significantly different from what it
became few years later.
The earliest C reference I have is cman74.pdf, currently at <http://cm.bell-labs.co/who/dmr/cman74.pdf>. It includes "extern" in
the list of keywords.
It was inherited from B, which had "extrn" as a keyword as of 1972.
On 2025-04-09, bart <bc@freeuk.com> wrote:
I'm not sure what your gripe is other than maybe I picked up on
something you got wrong. The discussion was about two struct types
like this:
typedef struct tag1 {...} T1;
typedef struct tag2 {...} T2;
and whether T1 and T2 were compatible or not. You said:
"and those types are not compatible, because the two struct tags
are different."
In this case the tags would be "tag1" and "tag2". I then said:
"I get an incompatible error (from the example you snipped) even
when I remove both struct tags."
When you remove the tag from a struct definition, the implementation
behaves as if it were implementing a unique tag which is different
from any other such tag, and any tag that can possibly be written
using textual syntax.
How did you implement tagless struct declarations in your compiler?
That means removing "tag1" and "tag2" so the example above looks
like this:
typedef struct {...} T1;
typedef struct {...} T2;
Here, you can't say the struct tags are different, as they are not
visible!
So if you close your eyes, two things that were different are now
no longer different, since they are invisible?
The tag is a property of the type, not of printed type declaration.
A struct type has a tag. If the declaration doesn't show one,
that doesn't mean it doesn't have a tag.
If a "Simulation" object has a "gravity" member, do you conclude
that a given simulation has no gravity, because the constructor
omitted specifying it?
Simulation s = new Simulation(windSpeed = 35.7)
As I concluded, your assertion about compatibility being based on
tags being the same or not didn't seem right.)
Or, you know, you could stop caring about what someone wrote in
comp.lang.c, be they right or wrong, and ... look it up?
On 2025-04-09, bart <bc@freeuk.com> wrote:
I'm not sure what your gripe is other than maybe I picked up on
something you got wrong. The discussion was about two struct types like
this:
typedef struct tag1 {...} T1;
typedef struct tag2 {...} T2;
and whether T1 and T2 were compatible or not. You said:
"and those types are not compatible, because the two struct tags are
different."
In this case the tags would be "tag1" and "tag2". I then said:
"I get an incompatible error (from the example you snipped) even when I
remove both struct tags."
When you remove the tag from a struct definition, the implementation
behaves as if it were implementing a unique tag which is different
from any other such tag, and any tag that can possibly be written
using textual syntax.
How did you implement tagless struct declarations in your compiler?
That means removing "tag1" and "tag2" so the example above looks like this: >>
typedef struct {...} T1;
typedef struct {...} T2;
Here, you can't say the struct tags are different, as they are not
visible!
So if you close your eyes, two things that were different are now
no longer different, since they are invisible?
The tag is a property of the type, not of printed type declaration.
A struct type has a tag. If the declaration doesn't show one,
that doesn't mean it doesn't have a tag.
If a "Simulation" object has a "gravity" member, do you conclude
that a given simulation has no gravity, because the constructor
omitted specifying it?
Simulation s = new Simulation(windSpeed = 35.7)
As I concluded, your assertion about compatibility being based on tags
being the same or not didn't seem right.)
Or, you know, you could stop caring about what someone wrote in
comp.lang.c, be they right or wrong, and ... look it up?
On Wed, 09 Apr 2025 14:44:39 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Wed, 9 Apr 2025 12:58:08 +0200
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
On 09.04.2025 11:42, David Brown wrote:
On 08/04/2025 18:28, bart wrote:
[...]
I believe the meaning of "extern" in combination with other
storage-class specifiers was picked to work with existing old
code from before "extern" was added to the language.
Assuming you mean the "C" language I don't quite understand the
last part of the sentence. Wasn't 'extern' already in "K&R" - so
what was "the language" before the addition of 'extern'?
Or did you just mean to say "[...] before _combinations_ of
'extern' and other storage-class specifier were added to the
language."
Janis, puzzled
K&R was published in 1978, 5 years after C got its first users.
Back in 1973-74 C language was significantly different from what it
became few years later.
The earliest C reference I have is cman74.pdf, currently at
<http://cm.bell-labs.co/who/dmr/cman74.pdf>. It includes "extern" in
the list of keywords.
It was inherited from B, which had "extrn" as a keyword as of 1972.
O.k. Then David Brown will have to look for different justification for
this particular misfeature of great majority of Unix implementations of
C language.
bart <bc@freeuk.com> writes:
[...]
Someone, not anyone but the all-knowing Tim, said: "and those types
are not compatible, because the two struct tags are different."
Do you agree with that? Or is there something more to making two types
be incompatible?
I don't recall the exact discussion
So currently, I have no explanation for why you may write "static int
foo; extern int foo;" and have "foo" be internal linkage, while "extern
int foo; static int foo;" is not allowed.
But if someone else has an explanation for this, or a realistic use-case
for static followed by extern, I am curious to hear about it.
On 10/04/2025 01:20, Kaz Kylheku wrote:
On 2025-04-09, bart <bc@freeuk.com> wrote:
I'm not sure what your gripe is other than maybe I picked up on
something you got wrong. The discussion was about two struct types like
this:
typedef struct tag1 {...} T1;
typedef struct tag2 {...} T2;
and whether T1 and T2 were compatible or not. You said:
"and those types are not compatible, because the two struct tags are
different."
In this case the tags would be "tag1" and "tag2". I then said:
"I get an incompatible error (from the example you snipped) even when I
remove both struct tags."
When you remove the tag from a struct definition, the implementation
behaves as if it were implementing a unique tag which is different
from any other such tag, and any tag that can possibly be written
using textual syntax.
How did you implement tagless struct declarations in your compiler?
That means removing "tag1" and "tag2" so the example above looks like this: >>>
typedef struct {...} T1;
typedef struct {...} T2;
Here, you can't say the struct tags are different, as they are not
visible!
So if you close your eyes, two things that were different are now
no longer different, since they are invisible?
The tag is a property of the type, not of printed type declaration.
Someone, not anyone but the all-knowing Tim, said: "and those types are
not compatible, because the two struct tags are different."
Do you agree with that? Or is there something more to making two types
be incompatible?
My examples included ones where tags /were/ different; tags which were identical (in nested scopes) and tags which were missing.
My view is that even if type discrimination was 100% dependent on tags,
source code (either tags don't exist, or they appear identical).
A struct type has a tag. If the declaration doesn't show one,
that doesn't mean it doesn't have a tag.
If a "Simulation" object has a "gravity" member, do you conclude
that a given simulation has no gravity, because the constructor
omitted specifying it?
Simulation s = new Simulation(windSpeed = 35.7)
This is quite irrelevant, since 'gravity' will be defined somewhere in
the source code, but you are talking about some internal attribute that
may or may not be used by an implementation.
As I concluded, your assertion about compatibility being based on tags
being the same or not didn't seem right.)
Or, you know, you could stop caring about what someone wrote in
comp.lang.c, be they right or wrong, and ... look it up?
Why don't you just tell me?
In my C compiler, each type has a unique index which is what is compared
to see if two types are the same type. It has nothing to do with tags.
This C code:
struct {int x;};
struct {int x;};
struct Tag {int x;};
{struct Tag {int x;};}
Produces these 4 distinct types, with indices 23-26:
In the message above Bart demonstrated that type of struct with
explicit tag depends not just on tag and fields, but also on
lexical scope.
IMHO, instead of going into irrelevant details, it is much simpler to postulate that all struct declarations within given translation unit
have different types.
If a "Simulation" object has a "gravity" member, do you conclude
that a given simulation has no gravity, because the constructor
omitted specifying it?
Simulation s = new Simulation(windSpeed = 35.7)
I am not quite understand how C++ is relevant.
On 2025-04-10, bart <bc@freeuk.com> wrote:
As far as different translation units go, there are rules. But most >implementations of C operate on faith: implementations see only
the type declarations in one translation unit being processed.
It is trusted that cross-translation-unit uses of types are compatible.
On 2025-04-10, bart <bc@freeuk.com> wrote:
Do you agree with that? Or is there something more to making two types
be incompatible?
Tim: two fingerprints from the left hand index finger are from different humans if they are different.
You: do you agree with this, or is there more that can make
two humans different?
Struct compatibility is determined by tag and content.
On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
So currently, I have no explanation for why you may write "static int
foo; extern int foo;" and have "foo" be internal linkage, while "extern
int foo; static int foo;" is not allowed.
What's also not allowed is "static int foo; int foo;" !
It's because "extern" means "refer to the existing file scope
declaration of the identifer if there is one propagating its
properties, including linkage; otherwise if it doesn't exist,
create an external linkage reference"
On 2025-04-10, bart <bc@freeuk.com> wrote:
In my C compiler, each type has a unique index which is what is compared
to see if two types are the same type. It has nothing to do with tags.
How can it not?
struct tag;
struct tag { ... };
these have to refer to the same type; how do you do that without tags?
Kaz Kylheku <643-408-1753@kylheku.com> writes:
On 2025-04-10, bart <bc@freeuk.com> wrote:
As far as different translation units go, there are rules. But most >>implementations of C operate on faith: implementations see only
the type declarations in one translation unit being processed.
It is trusted that cross-translation-unit uses of types are compatible.
And when they're not compatible, it can take _days_ to find the
bug. I was once called in to debug a random SIGSEGV in a large
crypto application (generated X.509 site certificates for most of the
world at the time). Turned out that different components of the
the application were linked against different versions of the crypto
library (a proprietary predecessor to openssl).
There have been a variety of things under discussion here, but I think
this particular one was about the linkage rules in C if an identifier is declared with "static int foo;" and/or "extern int foo;" and/or "int
foo;" at file scope, possibly in different orders. My thought was that
one influence on the rules was consistency of existing code after
"extern" was added to the language, but it seems unlikely since no one
knows of an early C without "extern".
So currently, I have no explanation for why you may write "static int
foo; extern int foo;" and have "foo" be internal linkage, while "extern
int foo; static int foo;" is not allowed. Given that neither are likely
to be of the remotest use, nor likely to be written by accident and go unnoticed, it should not affect anyone significantly.
But if someone else has an explanation for this, or a realistic use-case
for static followed by extern, I am curious to hear about it.
ATEOTD, to share such a type across two or more translation units, means
each one seeing its own definition of it. Nothing stops you having
somewhat different versions of it, as I had above, so this part has to
be taken on trust. This was part of my broader point that sharing
non-linkage named entities across modules in C was ad hoc.
On 10/04/2025 17:41, Kaz Kylheku wrote:
On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
So currently, I have no explanation for why you may write "static int
foo; extern int foo;" and have "foo" be internal linkage, while "extern
int foo; static int foo;" is not allowed.
What's also not allowed is "static int foo; int foo;" !
It's because "extern" means "refer to the existing file scope
declaration of the identifer if there is one propagating its
properties, including linkage; otherwise if it doesn't exist,
create an external linkage reference"
That's a summary of how "extern" works, but it results in a kind of
circular argument or tautology - it's just saying "extern means what it means". It does not explain /why/ it works this way, or where the rules came from, why C has use of a single keyword that works this way, and
why it is called "extern".
It would be much simpler if we had "static int x;" to mean "declare x
with internal linkage and define it", "extern int x;" to mean "declare x
to have extern linkage", and "int x;" to mean "declare x with external linkage and define it". That is how you use these in most circumstances (and there are gcc warning flags to enforce it, for those that want to
do that).
C rarely makes things more complicated without a good reason.
According to the C89 Rationale
On 4/10/25 15:14, James Kuyper wrote:
...
According to the C89 Rationale
Note: I have the C89 Rationale in PDF format. I an using an Ubuntu Linux machine, and am viewing the file with the "Document Viewer" program.
I
copied the text from that program, and pasted it into a Thunderbird
message window. All occurrences of "ff" and "fi" in the text got
converted to whitespace. Does anyone have any idea why that might have happened?
On 10/04/2025 20:05, David Brown wrote:
It would be much simpler if we had "static int x;" to mean "declare x
with internal linkage and define it", "extern int x;" to mean "declare x
to have extern linkage", and "int x;" to mean "declare x with external
linkage and define it". That is how you use these in most circumstances
(and there are gcc warning flags to enforce it, for those that want to
do that).
It can't be that simple in C because of shared headers.
If module A wants to export 'abc' to other modules, then the source code
seen by the compiler for A.c has to look like this:
extern int abc; // in A.h
......
int abc; // in A.c
The other modules include A.h and see 'extern int abc' which means 'abc'
is imported. But its home module sees both of these, including the
'extern' version, but here 'abc' is exported!
That is counter-intuitive: how can a module both import a name (via
'extern int') and export it (via 'int' without 'static')?
On 10/04/2025 17:41, Kaz Kylheku wrote:
On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
So currently, I have no explanation for why you may write "static int
foo; extern int foo;" and have "foo" be internal linkage, while "extern
int foo; static int foo;" is not allowed.
What's also not allowed is "static int foo; int foo;" !
It's because "extern" means "refer to the existing file scope
declaration of the identifer if there is one propagating its
properties, including linkage; otherwise if it doesn't exist,
create an external linkage reference"
That's a summary of how "extern" works, but it results in a kind of
circular argument or tautology - it's just saying "extern means what it
means". It does not explain /why/ it works this way, or where the rules
came from, why C has use of a single keyword that works this way, and
why it is called "extern".
It would be much simpler if we had "static int x;" to mean "declare x
with internal linkage and define it"
"extern int x;" to mean "declare x
to have extern linkage", and "int x;" to mean "declare x with external linkage and define it". That is how you use these in most circumstances
(and there are gcc warning flags to enforce it, for those that want to
do that).
C rarely makes things more complicated without a good reason. You gave
the example of using "extern" for "unshadowing" an identifier (thank you
for that example!), but it doesn't strike me as sufficient
justification. I had thought the reason for the way "extern" and
"static" interact was historical compatibility, but that does not appear
to be the case.
On 2025-04-10, bart <bc@freeuk.com> wrote:
ATEOTD, to share such a type across two or more translation units, means
each one seeing its own definition of it. Nothing stops you having
somewhat different versions of it, as I had above, so this part has to
be taken on trust. This was part of my broader point that sharing
non-linkage named entities across modules in C was ad hoc.
Nothing stops you because struct types are de-facto non-linkage
entities in the toolchain technology that is in widespread use.
Nothing stops an implementation from recording, into object files, info
that can be used to implement stricter type checking among
translation units at link time.
Here is one possible implementation.
All file-scope struct/union types are compiled in some kind of
struct/union table in the object file.
Those struct/union types are included which have been used as follows,
either directly or via nesting:
- in a parameter type of an external linkage function;
- in the return type of an external linkage function; or
- in the type of an object declared with external linkage.
In the table we have entries, say, consisting of the tag and, say,
tag name and, say, a 32 bit hash of the structure shape, taken over
all the members: their names, types, alignment and everything else
that influences compatibility.
Then, when linking, we merge all of the struct/union tables together. Whenever we see a tag that has a different 32 bit hash, that's a
conflict, and we report those two files with the different hashes as conflicting on their definition of the type indicated by the tag name.
The diagnostic dcould be given in tabular form, e.g:
error: 3 incompatible definitions of "struct foo" exist:
1: foo.o foo-helper.o
2: bar.o
3: stack.o queue.o
The rules for which types are included in the tables allow uses
where the types are not depended upon to be compatible.
Two mdoules can have a different "struct foo { ... }" at file scope,
which they each only use locally: neither module passes an
instance of its foo to the other module where it is interpreted
as that module's foo.
These exchanges happen via the arguments of external functions,
via global variables and via function returns. That's why we
suspect those places.
The rules could give rise to false positives, like when the
foo module has helper functions that take "struct foo *" and
are not called from outside of the module, but the helpers have not been declared static, and another module does the same thing, creating a
clash in the table entries.
That diagnostic would then be misleading; but it would still
indicate that something is not tidy in the program.
bart <bc@freeuk.com> writes:
On 10/04/2025 12:28, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
[...]
Someone, not anyone but the all-knowing Tim, said: "and those typesI don't recall the exact discussion
are not compatible, because the two struct tags are different."
Do you agree with that? Or is there something more to making two types >>>> be incompatible?
It stems from this, a reply from DB dated: "Tue, 8 Apr 2025 16:50:56
+0200". (About half way down there is some quoted code of mine.)
It concerned two struct types in different translations units, which
needed to be compatible for the test program to work corectly.
I said they were compatible enough. David said they were entirely
compatible. Tim said "No they are not". Three different opinions.
Either David or Tim was right; I don't much care which.
You were wrong.
There is no such thing as "compatible enough"; two types
either are compatible or are not compatible. I won't speculate on what
you might have meant by "compatible enough".
Either David or Tim was right; I don't much care which.
Do you have a URL for a PDF C89 Rationale?
On 09/04/2025 13:36, David Brown wrote:
On 09/04/2025 12:51, bart wrote:
Turning it around, you're saying that if T an U are incompatible types
within the same translation unit, they suddenly become compatible if
split across two translation units?
I'll have to think about this before replying to any other points.
Marvellous - I'd appreciate you putting more thought into this, and
less knee-jerk reactions and exaggerations. Please also read the
relevant parts of the standards before replying - at the very least,
section 6.2.7p1 and section 6.2.2. Once you have read these and tried
to understand them, it will be a lot easier to clear up any remaining
issues.
I'm not going to wade through reams of Standard minutiae, sorry.I
Are T and U compatible types are not? The answer must be unequivocal
without needing to be a 'standards-head'.
This has been said in this
thread:
BC: The types involved are somewhat different, but are compatible enough
   for it to work. [In that the member types, offsets and overall size,
   since pass-by-value is used, correspond]
DB: The two types are entirely compatible.
BC: Are they?
TR: No, they are not.
You say they're compatible, Tim Rentsch says they're not; who's right?
Kaz Kylheku <643-408-1753@kylheku.com> writes:
[...]
Where the rules came from is partially answered by the Rationale[...]
for ANSI C, where it discusses the various linkage models for external
names that were in the wild.
The "ISO-ized" version of the Rationale is found here:
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n850.pdf
N850 is an early version of the C9x (later C99) Rationale.
A later version is at
http://www.open-std.org/jtc1/sc22/WG14/www/C99RationaleV5.10.pdf
The example was like this:
module A: typedef struct point {float a; float b;} Point;
module B: typedef float length;
typedef struct _tag {length x, y;} vector;
David Brown said: "The two types are entirely compatible."
I said: "Are they?"
Tim Rentsch said: "No, they are not."
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
bart <bc@freeuk.com> writes:
[... compatibility of struct types ...]
The example was like this:
module A: typedef struct point {float a; float b;} Point;
module B: typedef float length;
typedef struct _tag {length x, y;} vector;
David Brown said: "The two types are entirely compatible."
I said: "Are they?"
Tim Rentsch said: "No, they are not."
I withdraw my earlier statement. Please leave me out of any
future discussion of the subject.
Do you mean that your earlier statement was incorrect (i.e., that
the types are compatible), or do you merely wish to pretend you
never said anything without taking a position on whether they're
compatible, or do you refuse to say?
Don't worry, I'm not planning to start or participate in a
lengthy discussion on your statement (that never turns out well).
I'm inviting you to clarify if you choose to do so. [...]
On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
On 10/04/2025 17:41, Kaz Kylheku wrote:
On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
So currently, I have no explanation for why you may write "static int
foo; extern int foo;" and have "foo" be internal linkage, while "extern >>>> int foo; static int foo;" is not allowed.
What's also not allowed is "static int foo; int foo;" !
It's because "extern" means "refer to the existing file scope
declaration of the identifer if there is one propagating its
properties, including linkage; otherwise if it doesn't exist,
create an external linkage reference"
That's a summary of how "extern" works, but it results in a kind of
circular argument or tautology - it's just saying "extern means what it
I would never be so sloppy as to leave the two ends of any argument
of mine dangling, not neatly closed into a circle.
means". It does not explain /why/ it works this way, or where the rules
came from, why C has use of a single keyword that works this way, and
why it is called "extern".
Where the rules came from is partially answered by the Rationale
for ANSI C, where it discusses the various linkage models for external
names that were in the wild.
The "ISO-ized" version of the Rationale is found here:
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n850.pdf
It would be much simpler if we had "static int x;" to mean "declare x
with internal linkage and define it"
There are sometimes reasons why we need a static forward
declarations for an object (not to mention function). Example:
static struct foo_operations;
static void foo_create_similar(struct foo *old_foo)
{
struct foo *new_foo = malloc(sizeof *foo);
...
// for whatever reason, this is not copied from old_foo
new_foo->ops = &foo_operations;
...
return foo;
}
static struct foo_operations = { ..., foo_clone, ... };
The function needs to refer to foo_operations for whatever reason, and the initialisation of foo_operations need the function.
"extern int x;" to mean "declare x
to have extern linkage", and "int x;" to mean "declare x with external
linkage and define it". That is how you use these in most circumstances
(and there are gcc warning flags to enforce it, for those that want to
do that).
So this describes the Strict Ref/Def model, like recommended in the K&R; but not reflecting restrictions actually implemented in the wild!
C rarely makes things more complicated without a good reason. You gave
the example of using "extern" for "unshadowing" an identifier (thank you
for that example!), but it doesn't strike me as sufficient
justification. I had thought the reason for the way "extern" and
"static" interact was historical compatibility, but that does not appear
to be the case.
Dennis Ritchie's 1975 C reference manual already describes a local use
of extern:
"In the extern case there must be an external definition (see below) for the
given identifiers somewhere outside the function in which they are declared."
This is the only mention of the extern specifier that Ritchie gives, indicating that it's not meant for file scope use (making external definitions).
About external definitions (what the "see below" refers to above), he writes:
"An external definition declares an identifier to have storage class extern
and a specified type."
He does not specify that this requires the extern specifier!
On 10/04/2025 21:25, James Kuyper wrote:
On 4/10/25 15:14, James Kuyper wrote:
...
According to the C89 Rationale
Note: I have the C89 Rationale in PDF format. I an using an Ubuntu Linux
machine, and am viewing the file with the "Document Viewer" program.
evince, presumably.
I
copied the text from that program, and pasted it into a Thunderbird
message window. All occurrences of "ff" and "fi" in the text got
converted to whitespace. Does anyone have any idea why that might have
happened?
ff and fi are common ligatures, so I suppose they're losing something in
the translation, and - just a guess - you may well have the same problem
with fl and ft.
On 10/04/2025 20:05, David Brown wrote:
On 10/04/2025 17:41, Kaz Kylheku wrote:
On 2025-04-10, David Brown <david.brown@hesbynett.no> wrote:
So currently, I have no explanation for why you may write "static int
foo; extern int foo;" and have "foo" be internal linkage, while "extern >>>> int foo; static int foo;" is not allowed.
What's also not allowed is "static int foo; int foo;" !
It's because "extern" means "refer to the existing file scope
declaration of the identifer if there is one propagating its
properties, including linkage; otherwise if it doesn't exist,
create an external linkage reference"
That's a summary of how "extern" works, but it results in a kind of
circular argument or tautology - it's just saying "extern means what
it means". It does not explain /why/ it works this way, or where the
rules came from, why C has use of a single keyword that works this
way, and why it is called "extern".
It would be much simpler if we had "static int x;" to mean "declare x
with internal linkage and define it", "extern int x;" to mean "declare
x to have extern linkage", and "int x;" to mean "declare x with
external linkage and define it". That is how you use these in most
circumstances (and there are gcc warning flags to enforce it, for
those that want to do that).
It can't be that simple in C because of shared headers.
If module A wants to export 'abc' to other modules, then the source code
seen by the compiler for A.c has to look like this:
    extern int abc;    // in A.h
    ......
    int abc;           // in A.c
The other modules include A.h and see 'extern int abc' which means 'abc'
is imported.
But its home module sees both of these, including the
'extern' version, but here 'abc' is exported!
That is counter-intuitive: how can a module both import a name (via
'extern int') and export it (via 'int' without 'static')?
You can't say that A.h is only for consumption by other modules, since
it could include stuff that all module including A will need, such as
macros, types and enums.
So, here C is complicated because the same attribute has to mean
different things depending on whether this is the entity's home module
or not.
C rarely makes things more complicated without a good reason.
C usually makes things more complicated without a good reason!
Here's one example, of dozens, of perfectly legal C:
 long unsigned const long const const typedef int A;
 int long unsigned const long const const typedef A;
 long unsigned const long const typedef int A;
 .....
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:
I withdraw my earlier statement. Please leave me out of any
future discussion of the subject.
Do you mean that your earlier statement was incorrect (i.e., that
the types are compatible), or do you merely wish to pretend you
never said anything without taking a position on whether they're
compatible, or do you refuse to say?
I am specifically _not_ saying either that my earlier statement
was right or that my earlier statement was wrong. My hope is
that henceforth people will act as though the statement never
entered the discussion. Does that clarify the matter for you?
That answers precisely what I was asking, thank you.
As often happens, I am mystified by your decision, but it is
unquestionably yours.
I'll try not to include you in any further discussion, but I do
not promise to try very hard.
Don't worry, I'm not planning to start or participate in a
lengthy discussion on your statement (that never turns out well).
I'm inviting you to clarify if you choose to do so. [...]
I appreciate the invitation and have made an earnest effort
to accommodate it.
An understanding of what "compatible types" means.
On 4/10/25 18:49, Keith Thompson wrote:
...
Do you have a URL for a PDF C89 Rationale?
No, I have it on disk, but I have no idea where I downloaded it from.
As a general rule, I download documents like that after seeing links
to them posted in usenet messages. It's current name is "C89.pdf",
but I probably renamed it from something less descriptive. Anyone who
wants a copy of unknown provenance, let me know.
On 10/04/2025 21:27, bart wrote:
On 10/04/2025 20:05, David Brown wrote:
C rarely makes things more complicated without a good reason.
C usually makes things more complicated without a good reason!
Nope.
Here's one example, of dozens, of perfectly legal C:
  long unsigned const long const const typedef int A;
  int long unsigned const long const const typedef A;
  long unsigned const long const typedef int A;
  .....
That is not more complicated, nor is it without good reason.
On Thu, 10 Apr 2025 17:59:15 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
An understanding of what "compatible types" means.
Bart didn't say that types are compatible or non-compatible.
He said that they are 'compatible enough'. That is not terminology of C Standard, but terminology of his own. And he seems to understand it.
In my own translation, 'compatible enough' means that when these structs
are accessed then any sane or even semi-sane compiler will generate code
that will have the same effect as in case of access through structures
with literally identical declarations.
On 4/10/25 18:49, Keith Thompson wrote:
...
Do you have a URL for a PDF C89 Rationale?
No, I have it on disk, but I have no idea where I downloaded it from. As
a general rule, I download documents like that after seeing links to
them posted in usenet messages. It's current name is "C89.pdf", but I >probably renamed it from something less descriptive. Anyone who wants a
copy of unknown provenance, let me know.
On 11/04/2025 10:17, David Brown wrote:
On 10/04/2025 21:27, bart wrote:
On 10/04/2025 20:05, David Brown wrote:
C rarely makes things more complicated without a good reason.
C usually makes things more complicated without a good reason!
Nope.
Here's one example, of dozens, of perfectly legal C:
  long unsigned const long const const typedef int A;
  int long unsigned const long const const typedef A;
  long unsigned const long const typedef int A;
  .....
That is not more complicated, nor is it without good reason.
Huh? That demonstrates several things:
1 That the same identifier can be redeclared multiple times
2 That 'typedef' needn't be on the left, but can be anywhere in the
middle of a type spec
3 That 'const' can also be anywhere inside the type spec
4 That duplicate 'const's are tolerated
5 That the three tokens ('int', 'unsigned' and two 'long's) denoting the
type can be be any order (and mixed up with other attributes)
I missed out:
6 'int' can be optionally omitted in this case.
That makes it pretty complicated to me! And I can't see that any of
these are necessary.
On 11/04/2025 13:51, bart wrote:
On 11/04/2025 10:17, David Brown wrote:
On 10/04/2025 21:27, bart wrote:
On 10/04/2025 20:05, David Brown wrote:
C rarely makes things more complicated without a good reason.
C usually makes things more complicated without a good reason!
Nope.
Here's one example, of dozens, of perfectly legal C:
  long unsigned const long const const typedef int A;
  int long unsigned const long const const typedef A;
  long unsigned const long const typedef int A;
  .....
That is not more complicated, nor is it without good reason.
Huh? That demonstrates several things:
1 That the same identifier can be redeclared multiple times
Many types of declarations can be repeated, as long as they define the
same identifier to be the same thing. If you want the details, they are
in section 6.7 of the standard.
2 That 'typedef' needn't be on the left, but can be anywhere in the
middle of a type spec
Correct. Putting it anywhere other than the left may be disallowed
sometime in the future (it is an "obsolescent feature"), but it is
currently supported in C.
3 That 'const' can also be anywhere inside the type spec
Correct.
4 That duplicate 'const's are tolerated
Correct.
5 That the three tokens ('int', 'unsigned' and two 'long's) denoting
the type can be be any order (and mixed up with other attributes)
Correct.
You seem to think that allowing a variation in the way a declaration is
made makes the feature "more complicated". That is simply incorrect.
The feature - the syntax and the rules in the language definition -
are /less/ complicated because of this flexibility. It means the syntax here can be, as given in 6.7p1 :
declaration-specifiers:
    storage-class-specifier declaration-specifiers opt
    type-specifier declaration-specifiers opt
    type-qualifier declaration-specifiers opt
    function-specifier declaration-specifiers opt
    alignment-specifier declaration-specifiers opt
If the order were to be strictly specified, there would need to be a half-dozen more named and defined specifier lists in the syntax.
It would certainly have been possible to specify an order - either in
the syntax or the constraints. I think that would have been a good
idea, and would make C code a little more consistent. But by the time
this was codified, there was probably a variety of orderings in use in
real code, and such ordering would make the standard, and therefore the language, a little more complicated.
I missed out:
6 'int' can be optionally omitted in this case.
That makes it pretty complicated to me! And I can't see that any of
these are necessary.
No one suggested it was at all necessary.
Does this copy have the same problems? https://www.open-std.org/jtc1/sc22/wg14/www/docs/n850.pdf
On 4/11/25 07:37, Michael S wrote:
...
Does this copy have the same problems? https://www.open-std.org/jtc1/sc22/wg14/www/docs/n850.pdf
No. For example, the first line containing "fi" is:
"3.Terms and definitions............................................................................................................6"
the "fi" in definitions required no fix up after cut-and-paste.
On 11/04/2025 15:25, David Brown wrote:
On 11/04/2025 13:51, bart wrote:
On 11/04/2025 10:17, David Brown wrote:
On 10/04/2025 21:27, bart wrote:
On 10/04/2025 20:05, David Brown wrote:
C rarely makes things more complicated without a good reason.
C usually makes things more complicated without a good reason!
Nope.
Here's one example, of dozens, of perfectly legal C:
  long unsigned const long const const typedef int A;
  int long unsigned const long const const typedef A;
  long unsigned const long const typedef int A;
  .....
That is not more complicated, nor is it without good reason.
Huh? That demonstrates several things:
1 That the same identifier can be redeclared multiple times
Many types of declarations can be repeated, as long as they define the
same identifier to be the same thing. If you want the details, they
are in section 6.7 of the standard.
2 That 'typedef' needn't be on the left, but can be anywhere in the
middle of a type spec
Correct. Putting it anywhere other than the left may be disallowed
sometime in the future (it is an "obsolescent feature"), but it is
currently supported in C.
3 That 'const' can also be anywhere inside the type spec
Correct.
4 That duplicate 'const's are tolerated
Correct.
5 That the three tokens ('int', 'unsigned' and two 'long's) denoting
the type can be be any order (and mixed up with other attributes)
Correct.
You seem to think that allowing a variation in the way a declaration
is made makes the feature "more complicated". That is simply
incorrect. The feature - the syntax and the rules in the language
definition - are /less/ complicated because of this flexibility. It
means the syntax here can be, as given in 6.7p1 :
declaration-specifiers:
     storage-class-specifier declaration-specifiers opt
     type-specifier declaration-specifiers opt
     type-qualifier declaration-specifiers opt
     function-specifier declaration-specifiers opt
     alignment-specifier declaration-specifiers opt
That always reads to me like 'lots of twisty windy passages, all alike'.
If the order were to be strictly specified, there would need to be a
half-dozen more named and defined specifier lists in the syntax.
This is the similar feature for my syntax, a bit of BNF:
 typedef = [scopeattr] 'type' name = typespec
It does a bit more than C's 'typedef' in that such names can be
exported, to render them visible to modules that import this one.
That makes it pretty complicated to me! And I can't see that any of
these are necessary.
No one suggested it was at all necessary.
/You/ did: "That is not more complicated, nor is it without good reason."
What are those good reasons, that it makes code more readable? That it
is easier to describe in a grammar?
That it makes it easier to parse?
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
On 4/10/25 18:49, Keith Thompson wrote:
...
Do you have a URL for a PDF C89 Rationale?
No, I have it on disk, but I have no idea where I downloaded it from. As
a general rule, I download documents like that after seeing links to
them posted in usenet messages. It's current name is "C89.pdf", but I >>probably renamed it from something less descriptive. Anyone who wants a >>copy of unknown provenance, let me know.
google sez:
http://port70.net/%7Ensz/c/c89/
scott@slp53.sl.home (Scott Lurndal) writes:
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
On 4/10/25 18:49, Keith Thompson wrote:
...
Do you have a URL for a PDF C89 Rationale?
No, I have it on disk, but I have no idea where I downloaded it
from. As a general rule, I download documents like that after
seeing links to them posted in usenet messages. It's current name
is "C89.pdf", but I probably renamed it from something less
descriptive. Anyone who wants a copy of unknown provenance, let me
know.
google sez:
http://port70.net/%7Ensz/c/c89/
John Mashey's thread there on 'long long' is intresting, particularly
point 4) weighing LLP64 (Windows) vs LP64 (unix). We had several
discussions during the Large File Summit about 64-bit C data types,
somewhat heated at times - but the existing implementations at the
time were all LP64 which won.
He also touches on a future 64 bit -> 128 bit transition, which is
still as far away now as it was three decades ago :-)
Aug 1995:
"I think I have good reason to believe that 128-bit-integer
machines are 25 years away, i.e., longer than the existence of
C..."
- John Mashey
"|> nightmares. Thus, "long long" is attractive *now*, but will
cause |> problems
|> with 128-bit architectures. 32-bit machines started to arrive
around 1978 |> and 64-bit machines around 1991 (my dates are
approximate). 128-bit |> machines will become available around
2004."
- Frank Farance
"Two declarations of structure, union, or enumerated types which ... use different tags declare distinct types. Each declaration of a structure, union, or enumerated type which does not include a tag declares a...
distinct type." (6.7.2.3p9).
On Wed, 9 Apr 2025 11:42:36 +0200
David Brown <david.brown@hesbynett.no> wrote:
In C, if you declare two structs in the same translation unit with
the same field types and the same field names, they are still
different types.
That is clear for structs with tags. Less clear for tagless structs
that have exactly the same fields.
On 11/04/2025 16:50, bart wrote:
declaration-specifiers:
     storage-class-specifier declaration-specifiers opt
     type-specifier declaration-specifiers opt
     type-qualifier declaration-specifiers opt
     function-specifier declaration-specifiers opt
     alignment-specifier declaration-specifiers opt
That always reads to me like 'lots of twisty windy passages, all alike'.
Try reading it without your usual anti-C prejudice. Perhaps read the
whole section of the standard.
If the order were to be strictly specified, there would need to be a
half-dozen more named and defined specifier lists in the syntax.
This is the similar feature for my syntax, a bit of BNF:
  typedef = [scopeattr] 'type' name = typespec
It does a bit more than C's 'typedef' in that such names can be
exported, to render them visible to modules that import this one.
The C syntax for declarations here is for /all/ declarations in C. It's
not just for typedefs in a simple little toy language.
are going to make absurd claims about your language in comparison to C,
you can expect to hear that it is a toy in comparison C.)
That it makes it easier to parse?
Who cares? That's irrelevant to the language design, except for toys
where the only user is the person who writes the tools.
On 09/04/2025 23:07, Tim Rentsch wrote:
bart <bc@freeuk.com> writes:
On 09/04/2025 00:27, Tim Rentsch wrote:
bart <bc@freeuk.com> writes:
If you want to make a point or ask a question about C code,
SHOW THE CODE. And show all of it. Don't make people guess by
showing only some of the code or by giving just a description.
I'm showing the code but you keep snipping it! [...]
No, I don't. Don't be so obtuse. I included the code I was
originally commenting on, in my first followup. My comment about
showing code was about your second posting. Let me repeat the
two important paragraphs (quoted above) taken from that posting:
I get an incompatible error (from the example you snipped)
even when I remove both struct tags.
The phrase "even when I remove both struct tags" describes code, it
doesn't show the code.
I showed this example a few lines later [in an earlier posting]
which has both struct tags omitted:
There is a simple lesson that you need to learn:
Please don't be patronising. We are not kids in your PL class.
On 4/10/25 20:40, James Kuyper wrote:
...
"Two declarations of structure, union, or enumerated types which ... use...
different tags declare distinct types. Each declaration of a structure,
union, or enumerated type which does not include a tag declares a
distinct type." (6.7.2.3p9).
I get the impression that the reason why the rules for compatible
struct, union, and enumerated types were defined the way they are might
not be obvious.
In C, within a single translation unit, there are three ways to define a >struct, union, or enumeration exactly once, and then use that type in >multiple locations:
1. Define the type with a tag, and then use that tag anywhere within its >scope to refer to the definition.
2. Define the type with a typedef, and then use that typedef anywhere
withing it's scope to refer to the definition.
3. Define the type in the "type-specifier" of a declaration with
multiple declarators. All of the declarators will share the definition
of that type.
On Thu, 10 Apr 2025 17:59:15 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
An understanding of what "compatible types" means.
Bart didn't say that types are compatible or non-compatible.
He said that they are 'compatible enough'. That is not terminology of C Standard, but terminology of his own. And he seems to understand it.
In my own translation, 'compatible enough' means that when these structs
are accessed then any sane or even semi-sane compiler will generate code
that will have the same effect as in case of access through structures
with literally identical declarations.
On 11/04/2025 16:24, David Brown wrote:
On 11/04/2025 16:50, bart wrote:
declaration-specifiers:
     storage-class-specifier declaration-specifiers opt
     type-specifier declaration-specifiers opt
     type-qualifier declaration-specifiers opt
     function-specifier declaration-specifiers opt
     alignment-specifier declaration-specifiers opt
That always reads to me like 'lots of twisty windy passages, all alike'.
Try reading it without your usual anti-C prejudice. Perhaps read the
whole section of the standard.
If the order were to be strictly specified, there would need to be a
half-dozen more named and defined specifier lists in the syntax.
This is the similar feature for my syntax, a bit of BNF:
  typedef = [scopeattr] 'type' name = typespec
It does a bit more than C's 'typedef' in that such names can be
exported, to render them visible to modules that import this one.
The C syntax for declarations here is for /all/ declarations in C.
It's not just for typedefs in a simple little toy language.
That's not right. You pasted part of 6.7p1. The full syntax for
declarations comprises all of 6.7.p1, plus 6.7.1p1, 6.7.2p1, 6.7.2p2 (constraints to do with the ordering of long, int etc), 6.7.2.1,
6.7.2.2, 6.7.3, 6.7.6, 6.7.7, and 6.7.8.
(And yes, if you
are going to make absurd claims about your language in comparison to
C, you can expect to hear that it is a toy in comparison C.)
Really? Please show /any/ declaration in C that I can't write in mine,
but in a saner and less convoluted manner. Please define /any/ data
structure that I can't express.
I could spend all day showing absurdity after absurdity in C. And you're saying /my/ language is a toy?!
That it makes it easier to parse?
Who cares? That's irrelevant to the language design, except for toys
where the only user is the person who writes the tools.
Humans have to parse it too. C must be the only non-esoteric language
where you need to use third-party tools (CDECL etc) to make sense of type-declarations. Either that or follow complex spirular algorithms to decade them.
I haven't remarked on:
7 That you need 3/4 tokens to specify a simple u64 type.
On 2025-04-11, Michael S <already5chosen@yahoo.com> wrote:
On Thu, 10 Apr 2025 17:59:15 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
An understanding of what "compatible types" means.
Bart didn't say that types are compatible or non-compatible.
He said that they are 'compatible enough'. That is not terminology of C
Standard, but terminology of his own. And he seems to understand it.
In my own translation, 'compatible enough' means that when these structs
are accessed then any sane or even semi-sane compiler will generate code
that will have the same effect as in case of access through structures
with literally identical declarations.
so struct { long x; } and struct { int x; } are compatible enough,
in situations that are portable enough.
On 2025-04-11, bart <bc@freeuk.com> wrote:,
I haven't remarked on:
7 That you need 3/4 tokens to specify a simple u64 type.
On the PC in front of me, two tokens are sufficient:
unsigned long
On 11/04/2025 18:56, bart wrote:
That's not right. You pasted part of 6.7p1. The full syntax for
declarations comprises all of 6.7.p1, plus 6.7.1p1, 6.7.2p1, 6.7.2p2
(constraints to do with the ordering of long, int etc), 6.7.2.1,
6.7.2.2, 6.7.3, 6.7.6, 6.7.7, and 6.7.8.
It is the full syntax for declaration specifiers - the matter under discussion. I did not include initialisation, static assertions, the
syntax for identifiers, or any number of different parts of the syntax
of C.
I could spend all day showing absurdity after absurdity in C. And
you're saying /my/ language is a toy?!
Yes.
It is a toy because it is a personal little language for your ego. There
is no specification or description of it, there are no serious implementations of it, there are no users of it other than you, there is
no consistency in it - you change your language and your tools to suit
the program you are writing at the time, and regularly don't know
yourself how it works or what features it has. It is in no sense "battle-tested" - the only user writes code that he knows will not cause trouble. Thus you avoid all the issues that real languages have to
handle - real programs written by many different people for many
different purposes.
You are like an Esperanto fanatic trying to tell people their language
is so much better than English because the spelling is consistent, so
the world would be a better place if we all switched over. Except in
your case, you are the only one who speaks the language.
I have never heard of anyone other than you who views cdecl as a
necessity. A tiny proportion of C programmers find it helpful when
dealing with code written by others - especially if the code is written
in a poor style and the reader is relatively new to C.
Rubbish. Everyone finds C declaration syntax a nightmare.
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.
Rubbish. I find C declaration syntax annoying, not a "nightmare".
bart <bc@freeuk.com> writes:
On 11/04/2025 22:36, Keith Thompson wrote:[...]
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.Rubbish. I find C declaration syntax annoying, not a "nightmare".
Annoying would be having to get letter case or punctuation just right.
So, yeah, a 'nightmare' is more apt than 'annoying'.
Bart, bart, bart.
You made a false statement about how *everyone* feels about
C's declaration syntax.
Humans have to parse it too. C must be the only non-esoteric languagewhere you need to use third-party tools (CDECL etc) to make sense of type-declarations. Either that or follow complex spirular algorithms to [decode] them.
We all know that you consider it to be
a nightmare. I don't think I've ever said or implied that you
shouldn't feel that way. You think everyone *should* find it
a nightmare? Fine.
You cannot possibly be so deluded that you think everyone feels
the same way as you do, and we're all lying about it.
You want to be treated better? Stop making deeply silly statements.
On 12/04/2025 00:59, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
On 11/04/2025 22:36, Keith Thompson wrote:[...]
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.Rubbish. I find C declaration syntax annoying, not a "nightmare".
Annoying would be having to get letter case or punctuation just right.
So, yeah, a 'nightmare' is more apt than 'annoying'.
Bart, bart, bart.
You made a false statement about how *everyone* feels about
C's declaration syntax.
So what would be a true statement? That everyone finds it at least midly annoying?
C type syntax is famous for being difficult and confusing; I think most
will agree about that. Even the creators said so.
bart <bc@freeuk.com> writes:
Rubbish. Everyone finds C declaration syntax a nightmare.
On 11/04/2025 22:36, Keith Thompson wrote:
Rubbish. I find C declaration syntax annoying, not a "nightmare".
Annoying would be having to get letter case or punctuation just right.
But C typepecs can go far beyond it. I can just about do arrays of
pointers, or pointers to arrays. Anything more complicated is pretty
much trial and error.
In an example in my post which I then deleted (DB will just ignore
examples), I wanted to create an array of 10 pointers to functions that
take an int and return an int.
I started with something like this that I recalled from memory
(otherwise it would be even more wrong):
int (*A)[10](int);
but CDECL said it was something different. I tried one or two more combinations before I gave up and asked CDECL to tell me the type from
the English.
C type syntax is just not fit for purpose.
This is not how a language is
meant to work, and this is not supposed to be the hard part of a
language! Syntax should be the easy bit.
This is that English spec (with the significant bits numbered):
array 10 pointer to func take int return int
1 2 3 4 5 6
Here is what CDECL came up with:
int (*A[10])(int);
6 3 1 2 4 5 (Not sure which bit is the '4')
The numbers below show the correspondence with the English. You can see
it's all over the place. This is how I'd write it in another actual
language syntax:
[10]ref func(int)int A
1 2 3 4 5 6
Notice that that numbering here exactly corresponds to the English. THIS
is how easy it should be. I could write this as fast as I can type.
Further, the variable name is well out of it. In my syntax, any names go
on the right; names on the left is also popular. But no language other
than C and C++ has names IN THE MIDDLE.
So, yeah, a 'nightmare' is more apt than 'annoying'.
bart <bc@freeuk.com> writes:
Rubbish. Everyone finds C declaration syntax a nightmare.
Because of "C"'s somewhat convoluted (IMO "bad") syntax it might
help you to make use of 'typedef's to incrementally construct your
types!
C type syntax is just not fit for purpose.
Reality shows that it *is* (de facto) "fit for purpose". (Probably
not yours. - I'm still wondering why you act in a "C" newsgroup.)
This is not how a language is
meant to work, and this is not supposed to be the hard part of a
language! Syntax should be the easy bit.
I agree that language designers can do a much better job. (There's
quite some examples for languages with an IMO "better" syntax.)
This is that English spec (with the significant bits numbered):
array 10 pointer to func take int return int
My English might not be good enough, but in my book this is not an
English sentence and for me not (not much)
Guessing: An array with 10 elements that are pointers to functions
that take an 'int' parameter and return an 'int' value?
1 2 3 4 5 6
Here is what CDECL came up with:
int (*A[10])(int);
6 3 1 2 4 5 (Not sure which bit is the '4')
(This opening parenthesis syntactically indicates the function, as
also indicated by the numberings above. - Or so I'd think. - No?)
The numbers below show the correspondence with the English. You can see
it's all over the place. This is how I'd write it in another actual
language syntax:
[10]ref func(int)int A
1 2 3 4 5 6
And what should that mean? - You know, since I haven't identified
your "English sentence" as a clearly understandable English sentence
I'm lost here, since I don't know that (your?) language. - For the
"C" case I could at least read the "C" specs (in case I got lost).
Assumed that my guess above was correct that's quite equivalent to
the Algol 68 form
[10] REF PROC (INT) INT a
but in Algol 68 you'd probably rather use it without the unnecessary "pointer"/reference just as in
[10] PROC (INT) INT a
which - as you seem to like clearness - is even simpler!
On 2025-04-12, bart <bc@freeuk.com> wrote:
C type syntax is famous for being difficult and confusing; I think most
will agree about that. Even the creators said so.
If you had a function that takes an int, that returned a pointer to an
array, how would you pass in 42, and then get at the third element?
f(42) // gets the pointer to the array
(*f(42)) // designates the array
(*f(42))[2] // gets at the third element.
Ok, now declaring a function of int, which returns a pointer to an array
of 16 elements:
(*f(int))[16];
Notice any resemblance? The 42 argumet has changed to a type specifier
for the corresponding parameter type. The array reference turns into
the size. Minor!
We need a type specifier to the elements:
double (*f(int))[16];
Declaration follows use: it's not just a slogan, it's real!
If you don't like the declaration syntax, it's possibly because
you don't like the expression syntax for working with pointer
dereferencing and arrays, which it mirrors. (You not liking
C expression syntax: billion to one odds, right?)
IDEA: maybe you would like the "dedclaration follows use", if it was
rendered over a different expression grammar in which pointer, arrays
and whatnot work the way you like. If didn't dislike the "use",
you might not dislike "declaration follows use".
Now, from this "envelope shape":
double (.......)[16];
we know that whatever ..... is, it is an array of 16 doubles.
This .... is called a "type hole" by functional programmers working
in Haskell and whatnot.
If we replace the hole with a name like abc:
double (abc)[16];
then what is being declared is that name. We get an object abc which is
such an array. The parentheses are then unnecessary and we can drop
them.
If we plug in *f(int) instead of abc, then *f(int) isn't what is
being declared: f is. But we know that when this f is called, and the
On 11/04/2025 22:36, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.
Rubbish. I find C declaration syntax annoying, not a "nightmare".
Annoying would be having to get letter case or punctuation just right.
But C typepecs can go far beyond it. I can just about do arrays of
pointers, or pointers to arrays. Anything more complicated is pretty
much trial and error.
In an example in my post which I then deleted (DB will just ignore
examples), I wanted to create an array of 10 pointers to functions that
take an int and return an int.
On 12/04/2025 03:43, Kaz Kylheku wrote:
On 2025-04-12, bart <bc@freeuk.com> wrote:
C type syntax is famous for being difficult and confusing; I think most
will agree about that. Even the creators said so.
If you had a function that takes an int, that returned a pointer to an
array, how would you pass in 42, and then get at the third element?
f(42) // gets the pointer to the array
(*f(42)) // designates the array
(*f(42))[2] // gets at the third element.
Ok, now declaring a function of int, which returns a pointer to an array
of 16 elements:
(*f(int))[16];
Notice any resemblance? The 42 argumet has changed to a type specifier
for the corresponding parameter type. The array reference turns into
the size. Minor!
We need a type specifier to the elements:
double (*f(int))[16];
Declaration follows use: it's not just a slogan, it's real!
I'm sorry, but it doesn't work! The thought processes are entirely
different between writing expressions, and declaring types. They differ
in many ways anyway:
* A typespec needs a base type; an expr doesn't
* A typespec needs to express the whole thing right up to the base type;
an expr can be partial
* A typespec can include 'const' and other attributes; an expr doesn't
* A typespec uses '*' for pointers, an expr can use '*' or '[]' to deref
* A typespec uses '[]' for arrays; an expression can choose to use '*'
to index
* A typespec uses (*) for function pointers, but an expression can
choose to omit both that * and the accompanying ().
C doesn't directly have the means to centralise a common type, you have
to do:
typedef int (*Arr)[10];
Arr A, B, C;
or:
typeof(int (*)[10]) , B, C
Here there is a clear (and clean!) disconnect between each variable, and
its type. A variable's type shouldn't be something it has to 'wear'
wrapped around it, so that it literally looks like an expression. That
would be a bizarre concept.
On 2025-04-12, bart <bc@freeuk.com> wrote:
On 12/04/2025 03:43, Kaz Kylheku wrote:
On 2025-04-12, bart <bc@freeuk.com> wrote:
C type syntax is famous for being difficult and confusing; I think most >>>> will agree about that. Even the creators said so.
If you had a function that takes an int, that returned a pointer to an
array, how would you pass in 42, and then get at the third element?
f(42) // gets the pointer to the array
(*f(42)) // designates the array
(*f(42))[2] // gets at the third element.
Ok, now declaring a function of int, which returns a pointer to an array >>> of 16 elements:
(*f(int))[16];
Notice any resemblance? The 42 argumet has changed to a type specifier
for the corresponding parameter type. The array reference turns into
the size. Minor!
We need a type specifier to the elements:
double (*f(int))[16];
Declaration follows use: it's not just a slogan, it's real!
I'm sorry, but it doesn't work! The thought processes are entirely
different between writing expressions, and declaring types. They differ
in many ways anyway:
The main difference is that the the expressions are the payload that
does the work, whereas declarations are just mental overead.
The thought process is that the C programmer has a data structure
layout in their mind and can write expressions to navigate through
it, from the top-level reference down to its leaves.
But, oh crap, the C programmer has to declare the things they are using
in that expression.
C brings a nice simplification here. If you can write the expression to access the thing you are imagining, the declaration can be derived
from that shape.
* A typespec needs a base type; an expr doesn't
* A typespec needs to express the whole thing right up to the base type;
an expr can be partial
* A typespec can include 'const' and other attributes; an expr doesn't
* A typespec uses '*' for pointers, an expr can use '*' or '[]' to deref
* A typespec uses '[]' for arrays; an expression can choose to use '*'
to index
* A typespec uses (*) for function pointers, but an expression can
choose to omit both that * and the accompanying ().
"Declaration follow use" is not perfect or absolute, but it helps
exactly with the confusing cases with mlutiple levels of pointers,
arrays and functions.
C doesn't directly have the means to centralise a common type, you have
to do:
typedef int (*Arr)[10];
Arr A, B, C;
or:
typeof(int (*)[10]) , B, C
Why would you showing two ways how C has the direct means to centralize
a common array type, to illustrate the claim that it doesn't?
Here there is a clear (and clean!) disconnect between each variable, and
its type. A variable's type shouldn't be something it has to 'wear'
wrapped around it, so that it literally looks like an expression. That
would be a bizarre concept.
If you had thought of it first, you'd think it's brilliant.
Dennis Ritchie really showed us a nice way to deal with messes
of pointers, arrays and function pointers.
On 12/04/2025 01:13, bart wrote:
On 11/04/2025 22:36, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.
Rubbish. I find C declaration syntax annoying, not a
"nightmare".
Annoying would be having to get letter case or punctuation just
right.
But C typepecs can go far beyond it. I can just about do arrays
of pointers, or pointers to arrays. Anything more complicated
is pretty much trial and error.
In an example in my post which I then deleted (DB will just
ignore examples), I wanted to create an array of 10 pointers to
functions that take an int and return an int.
If only C had a way to make that simple and clear.
 Oh, wait - it
does.
    typedef int (*FIntInt)(int);
    FIntInt funcs[10];
On 12/04/2025 13:39, David Brown wrote:
On 12/04/2025 01:13, bart wrote:
On 11/04/2025 22:36, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.
Rubbish. I find C declaration syntax annoying, not a "nightmare".
Annoying would be having to get letter case or punctuation just right.
But C typepecs can go far beyond it. I can just about do arrays of
pointers, or pointers to arrays. Anything more complicated is pretty
much trial and error.
In an example in my post which I then deleted (DB will just ignore
examples), I wanted to create an array of 10 pointers to functions
that take an int and return an int.
If only C had a way to make that simple and clear.
But... but... but...!!!
 Oh, wait - it does.
...Finally!
     typedef int (*FIntInt)(int);
     FIntInt funcs[10];
Just one tiny point, though. I've never been a fan of hiding pointers
behind typedefs. I would much prefer:
typedef int FIntInt(int);
FIntInt *funcs[10];
Better to have those *s out in the open, where we can keep an eye on them.
On 12/04/2025 00:59, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
On 11/04/2025 22:36, Keith Thompson wrote:[...]
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.Rubbish. I find C declaration syntax annoying, not a "nightmare".
Annoying would be having to get letter case or punctuation just right.
So, yeah, a 'nightmare' is more apt than 'annoying'.Bart, bart, bart.
You made a false statement about how *everyone* feels about
C's declaration syntax.
So what would be a true statement? That everyone finds it at least
midly annoying?
On 12/04/2025 00:59, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
On 11/04/2025 22:36, Keith Thompson wrote:[...]
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.Rubbish. I find C declaration syntax annoying, not a "nightmare".
Annoying would be having to get letter case or punctuation just right.
So, yeah, a 'nightmare' is more apt than 'annoying'.
Bart, bart, bart.
You made a false statement about how *everyone* feels about
C's declaration syntax.
So what would be a true statement? That everyone finds it at least midly annoying?
C type syntax is famous for being difficult and confusing; I think most
will agree about that. Even the creators said so.
This was the discussion:
BC:
Humans have to parse it too. C must be the only non-esoteric languagewhere you need to use third-party tools (CDECL etc) to make sense of type-declarations. Either that or follow complex spirular algorithms to [decode] them.
DB:
I have never heard of anyone other than you who views cdecl as a necessity.
So, is that last statement true or not?
I didn't say it was a necessity,
but that you need to use such tools or special methods to understand
them. And clearly, that would be the more complicated ones; people can usually cope with 'int'.
I replied to one sweeping statement with another.
You want to be treated better? Stop making deeply silly statements.
DB was making light of the type syntax issue and pretty much dismissed
it out of hand. How should I have responded?
Not that it would cut any ice with him. Nothing is ever that complicated
or too onerous or too slow or too over the top or too badly designed or ...
I suggest also that you stop taking throwaway comments too literally.
Yet, there is probably more truth in my remark than in David's.
You might also consider that while many features of C have been copied,
I don't know of any language that has copied its type syntax.
I wonder why? Do you think the designers had an opinion about it closer
to mine, or to David Brown's?
On 12/04/2025 01:13, bart wrote:
On 11/04/2025 22:36, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.
Rubbish. I find C declaration syntax annoying, not a "nightmare".
Annoying would be having to get letter case or punctuation just right.
But C typepecs can go far beyond it. I can just about do arrays of
pointers, or pointers to arrays. Anything more complicated is pretty
much trial and error.
In an example in my post which I then deleted (DB will just ignore
examples), I wanted to create an array of 10 pointers to functions
that take an int and return an int.
If only C had a way to make that simple and clear. Oh, wait - it does.
    typedef int (*FIntInt)(int);
typedef int ((*FIntInt))(int);
    FIntInt funcs[10];
If a C programmer - such as yourself - is foolish enough to reject parts
of the language designed to make coding simpler, safer, clearer and more portable, then I can see how your self-imposed restrictions make your
coding harder. But the fault lies in the poor use of the language, not
the language.
designed to make coding simpler, safer, clearer and more
bart <bc@freeuk.com> writes:
On 12/04/2025 00:59, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
On 11/04/2025 22:36, Keith Thompson wrote:[...]
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.Rubbish. I find C declaration syntax annoying, not a "nightmare".
Annoying would be having to get letter case or punctuation just right.
So, yeah, a 'nightmare' is more apt than 'annoying'.Bart, bart, bart.
You made a false statement about how *everyone* feels about
C's declaration syntax.
So what would be a true statement? That everyone finds it at least
midly annoying?
That there's a wide variety of opinions on the matter, just as there is
on just about every issue. The fact that C is one of the most widely
used languages should clue you in to the fact that large numbers of
people find it far less troublesome than you do,
On 12/04/2025 15:21, Richard Heathfield wrote:
On 12/04/2025 13:39, David Brown wrote:
     typedef int (*FIntInt)(int);
     FIntInt funcs[10];
Just one tiny point, though. I've never been a fan of hiding
pointers behind typedefs. I would much prefer:
typedef int FIntInt(int);
FIntInt *funcs[10];
Better to have those *s out in the open, where we can keep an
eye on them.
C is a flexible language, and also caters for those that have
heretical opinions. I have no use of a function type in a
language that does not treat functions as first class objects -
you cannot pass a function as a parameter, return one from a
function, or even have a function object. You always deal with
pointers to functions.
On 12/04/2025 03:27, bart wrote:
C type syntax is famous for being difficult and confusing; I think
most will agree about that. Even the creators said so.
I disagree with that claim. I think it is probably fair to say that advanced, complicated and multi-layer types are difficult in any
programming language.
To be clear - I think putting a complicated type declaration on a single
line makes code harder to read.
A vast number of people have written a vast amount of code in C. Clearly
it is /not/ too complicated, or onerous, or slow.
I have said multiple times that if I were to design a new programming language, its syntax would differ significantly from C's.
On 12/04/2025 14:43, David Brown wrote:
On 12/04/2025 03:27, bart wrote:
C type syntax is famous for being difficult and confusing; I think
most will agree about that. Even the creators said so.
I disagree with that claim. I think it is probably fair to say that
advanced, complicated and multi-layer types are difficult in any
programming language.
But a type that is a simple linear chain should be straightforward, and usually is, just not in C. That was illustrated here:
array of 10 pointer to function taking int and returning int
1 2 3 4 5 6
I have said multiple times that if I were to design a new programming
language, its syntax would differ significantly from C's.
But it would be a toy unless you could get it adopted by lots of people.
By your standards, even a DSL that you create for use in your
professional work would be a toy.
With LTR syntax, you can create arbitrarily complex chains, and you will always now exactly what they mean, and which * is which. Modifying them
is trivial:
  C                 LTR style
  int *(*A)[]       *[]*[]int A        # ptr to array of ptr to int
On 2025-04-12, bart <bc@freeuk.com> wrote:
On 12/04/2025 14:43, David Brown wrote:
On 12/04/2025 03:27, bart wrote:
C type syntax is famous for being difficult and confusing; I think
most will agree about that. Even the creators said so.
I disagree with that claim. I think it is probably fair to say that
advanced, complicated and multi-layer types are difficult in any
programming language.
But a type that is a simple linear chain should be straightforward, and
usually is, just not in C. That was illustrated here:
array of 10 pointer to function taking int and returning int
1 2 3 4 5 6
You make a good point in that since the type constructing operators are
unary (prefix or postfix), the derivation chain is linear and could be linearized, without the need for any precedence parentheses.
It follows the use, though.
The function and array derivations are postfix. Only the pointer
derivation is prefix.
If we imagine a C with postfix pointer dereferencing, say using ^
(setting aside the xor meaning for a moment), like:
a[i]^(arg); // index into a at i, dereference, call with arg.
Then the declarator would be similar under declaration-follows-use:
int a[10]^(int); // same as int (*a[10])(int);
Then, suppose if you didn't want an array of pointers, but
a pointer to an array, you would not add, remove or rearrange
precedence parentheses. You would just reorder the postfixes.
int a^[10](int) // same as int (*a)[10](int);
// Note: invalid! For syntactic discussion only!
This is a type not supported in C: array of functions.
You do have a point, but the fact that C declarations follow C
expressions (even with the way suboptimal dereferencing is on the left)
is a good thing. The consistency makes it easy to learn declarations,
and also to visually check code for sanity: do declarations match uses.
If the DSL reinvents a lot of risky wheels, like doing everything
from scratch, that could be the case. It takes some years to mature
something out of non-toy status at that level.
On 2025-04-12, bart <bc@freeuk.com> wrote:
[...]
The main difference is that the the expressions are the payload that
does the work, whereas declarations are just mental overead.
The thought process is that the C programmer has a data structure
layout in their mind and can write expressions to navigate through
it, from the top-level reference down to its leaves.
But, oh crap, the C programmer has to declare the things they are using
in that expression.
C brings a nice simplification here. If you can write the expression to access the thing you are imagining, the declaration can be derived
from that shape.
On 12/04/2025 05:33, Janis Papanagnou wrote:
[ 'typedef' composition/decomposition for complex declarations ]
This is a third kind of workround. All of them should be unnecessary.
Unless the type really is complicated and needs to be decomposed anyway, whatever the syntax.
[...]
But I also 100% hate its syntax and various other bits and pieces. (OK,
about 80% then.)
[...
And APIs use C type syntax. So, yeah, I am entitled to an opinion about it.
[...]
Guessing: An array with 10 elements that are pointers to functions
that take an 'int' parameter and return an 'int' value?
[...]
(This opening parenthesis syntactically indicates the function, as
also indicated by the numberings above. - Or so I'd think. - No?)
Not necessarily. This is a valid declaration in C:
int (A);
That opening parentheses is just noise. (I guess you just learned
something new about C today?)
Assumed that my guess above was correct that's quite equivalent to
the Algol 68 form
[10] REF PROC (INT) INT a
So you do get it (maybe I should have read this far first). Yes, it
directly comes from Algol68.
But left-to-right type specifications must be common now everywhere.
but in Algol 68 you'd probably rather use it without the unnecessary
"pointer"/reference just as in
[10] PROC (INT) INT a
which - as you seem to like clearness - is even simpler!
This is not as clear; the intent is to have a reference to a function;
not an array of actual functions. For example:
[]ref func(int) int := (F, G, H)
It is initialised to functions F, G, H which are defined elsewhere.
Maybe in Algol68 you can have actual function definitions in that list.
But not in mine, which was created as a leaner, simpler and more
transparent systems language.
On 12.04.2025 13:00, bart wrote:
[]ref func(int) int := (F, G, H) # [var name missing]
It is initialised to functions F, G, H which are defined elsewhere.
In Algol 68 I can just write (without 'REF'), for example,
[10] PROC (INT) INT apfii;
PROC one_less = (INT i) INT : i-1;
PROC one_more = (INT i) INT : i+1;
apfii[2:3] := ( one_less, one_more );
We don't need "pointers" (or references) which don't contribute to the clearness of the semantics for this purpose - 'REF's are used for other things -, for the case here they'd rather introduce low-level mechanics unnecessarily in the application. - Just saying. (I'm not intending to complain in that respect about "C" or about "your language". I'm merely reporting some simple facts about it.) - So the 'ref' necessity in your language may look clear to you but for me it's just obscuring ballast.
But not in mine, which was created as a leaner, simpler and more
transparent systems language.
We obviously disagree about the "transparence". I prefer languages that
don't make me have to use unnecessarily low-level mechanics. There's no necessity of "ref" here; that's a problem of (or a "solution" or maybe "workaround" in, or a design decision of) your language.
- But as many
others here, I anyway don't care much about other's personal languages.
Algol68 fits the role of systems language;
On 12.04.2025 13:00, bart wrote:
But I also 100% hate its syntax and various other bits and pieces. (OK,
about 80% then.)
(I also don't like its syntax too much. I think I'm just complaining
less than you about that. BTW, I've got the impression that all the shortcomings of "C" are well known by most regulars here; they just
handle these facts in discussions differently than you.)
On 12/04/2025 17:32, Richard Heathfield wrote:
function object. You always deal with pointers to functions.
That's a perfectly valid reason to prefer your way, and mine is a
perfectly valid reason to prefer mine. TMTOWTDI.
On 13/04/2025 12:33, bart wrote:
Algol68 fits the role of systems language;
It somehow lost the word 'poorly'!
On 12/04/2025 14:52, David Brown wrote:
On 12/04/2025 15:21, Richard Heathfield wrote:
On 12/04/2025 13:39, David Brown wrote:
<snip>
     typedef int (*FIntInt)(int);
     FIntInt funcs[10];
Just one tiny point, though. I've never been a fan of hiding pointers
behind typedefs. I would much prefer:
typedef int FIntInt(int);
FIntInt *funcs[10];
Better to have those *s out in the open, where we can keep an eye on
them.
C is a flexible language, and also caters for those that have
heretical opinions. I have no use of a function type in a language
that does not treat functions as first class objects - you cannot pass
a function as a parameter, return one from a function, or even have a
function object. You always deal with pointers to functions.
That's a perfectly valid reason to prefer your way, and mine is a
perfectly valid reason to prefer mine. TMTOWTDI.
On 13/04/2025 03:27, Janis Papanagnou wrote:
On 12.04.2025 13:00, bart wrote:
But I also 100% hate its syntax and various other bits and pieces. (OK,
about 80% then.)
(I also don't like its syntax too much. I think I'm just complaining
less than you about that. BTW, I've got the impression that all the
shortcomings of "C" are well known by most regulars here; they just
handle these facts in discussions differently than you.)
The shortcomings are downplayed considerably. Especially in discussions involving me because they don't like it whenever someone states the obvious.
But also, most here have to use it professionally, so have learned to
work around it.
bart <bc@freeuk.com> writes:
On 13/04/2025 12:33, bart wrote:
Algol68 fits the role of systems language;
It somehow lost the word 'poorly'!
That would suprise Burroughs/Unisys, where the operating
system, database and utilites are all written in Algol.
On 2025-04-13, bart <bc@freeuk.com> wrote:
On 13/04/2025 03:27, Janis Papanagnou wrote:
On 12.04.2025 13:00, bart wrote:
But I also 100% hate its syntax and various other bits and pieces. (OK, >>>> about 80% then.)
(I also don't like its syntax too much. I think I'm just complaining
less than you about that. BTW, I've got the impression that all the
shortcomings of "C" are well known by most regulars here; they just
handle these facts in discussions differently than you.)
The shortcomings are downplayed considerably. Especially in discussions
involving me because they don't like it whenever someone states the obvious. >>
But also, most here have to use it professionally, so have learned to
work around it.
There are lots of examples of people just liking C.
Oh, Donald Knuth, in a 1993 Computer Literacy Bookshops interview:
CLB: Did you integrate WEB with C because so many programmers today
are using it, or do you personally like C and write with it?
Knuth: I think C has a lot of features that are very important. The
way C handles pointers, for example, was a brilliant innovation; it
solved a lot of problems that we had before in data structuring and
made the programs look good afterwards. C isn't the perfect language,
no language is, but I think it has a lot of virtues, and you can avoid
the parts you don't like.
because it blends in with the operating system (if you're using UNIX,
for example).
All through my life, I've always used the programming language that
blended best with the debugging system and operating system that I'm
using. If I had a better debugger for language X, and if X went well
with the operating system, I would be using that.
Richard Stallman of the GNU Project: developed a C compiler and started cloning Unix in the mid 1980's, entirely as free software.
Billions of lines have been written in C as free open source since.
The reason some people have to use it for work is, ironically, is that people's unpaid side projects evolved into widely deployed platforms
that the world relies on.
C has spawned imitation in the form of "C like" languages, that all
started as grenfield projects that could have chosen any syntax
they wanted.
bart <bc@freeuk.com> writes:
[...]
8 A u64 type can be denoted as either 'uint64_t' OR as some
combination of the tokens (long, long, unsigned, [int])
"uint64_t" and "unsigned long long int" do not mean the same thing.
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.
I don't.
On 2025-04-11, Michael S <already5chosen@yahoo.com> wrote:
On Thu, 10 Apr 2025 17:59:15 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
An understanding of what "compatible types" means.
Bart didn't say that types are compatible or non-compatible.
He said that they are 'compatible enough'. That is not terminology
of C Standard, but terminology of his own. And he seems to
understand it.
In my own translation, 'compatible enough' means that when these
structs are accessed then any sane or even semi-sane compiler will
generate code that will have the same effect as in case of access
through structures with literally identical declarations.
so struct { long x; } and struct { int x; } are compatible enough,
in situations that are portable enough.
A sphere and a cow are similar enough, ...
On Fri, 11 Apr 2025 11:15:44 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
bart <bc@freeuk.com> writes:
[...]
8 A u64 type can be denoted as either 'uint64_t' OR as some
combination of the tokens (long, long, unsigned, [int])
"uint64_t" and "unsigned long long int" do not mean the same thing.
And it's a PITA.
On 2025-04-12, bart <bc@freeuk.com> wrote:
On 12/04/2025 14:43, David Brown wrote:
On 12/04/2025 03:27, bart wrote:
C type syntax is famous for being difficult and confusing; I
think most will agree about that. Even the creators said so.
I disagree with that claim. I think it is probably fair to say
that advanced, complicated and multi-layer types are difficult in
any programming language.
But a type that is a simple linear chain should be straightforward,
and usually is, just not in C. That was illustrated here:
array of 10 pointer to function taking int and returning int
1 2 3 4 5 6
You make a good point in that since the type constructing operators
are unary (prefix or postfix), the derivation chain is linear and
could be linearized, without the need for any precedence parentheses.
It follows the use, though.
On 13/04/2025 19:57, Michael S wrote:
On Fri, 11 Apr 2025 11:15:44 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
bart <bc@freeuk.com> writes:
[...]
8 A u64 type can be denoted as either 'uint64_t' OR as some
combination of the tokens (long, long, unsigned, [int])
"uint64_t" and "unsigned long long int" do not mean the same thing.
And it's a PITA.
There is only one thing I find a little bit annoying about the sized
integer types in C - the printf specifiers.
I tend to "cheat" with
these, using "%lu" for uint32_t on the targets I usually use, where I
know uint32_t is "long unsigned int". Other than that, I stick to
the size-specific types for much of my code except local "throw-away" variables that might be "int". Compatibility or lack thereof between
the size-specific types and the standard integer types is simply
irrelevant in my code.
The funny thing is that in original C prefix form of [] indexing was equivalent to the postfix form. May be, it still is in C23, I didn't
try to look in the docs or test.
On 2025-04-13, Michael S <already5chosen@yahoo.com> wrote:
The funny thing is that in original C prefix form of [] indexing was equivalent to the postfix form. May be, it still is in C23, I
didn't try to look in the docs or test.
Are you thinking of a[i] being *(a + i) being i[a] due to
commutativity?
That's really not a useful feature. Actually right down to a + i being commutative when a is a pointer. It would be fine if only the
<pointer> + <integer> combination were allowed.
On Sat, 12 Apr 2025 17:40:25 -0000 (UTC)...
The funny thing is that in original C prefix form of [] indexing was equivalent to the postfix form. May be, it still is in C23, I didn't
try to look in the docs or test.
However in type declarations one always had to use only postfix form.
On Fri, 11 Apr 2025 18:24:41 -0400
James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
bart <bc@freeuk.com> writes:
[...]
Rubbish. Everyone finds C declaration syntax a nightmare.
I don't.
Combination of prefix and postfix modifiers in C decarations is hard to follow for majority of C users. If for you it is easy then you belong to minoity.
My impression rfrom old books was that indexing as [i]arr was (is ?)
also legal.
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
On 4/13/25 17:30, Michael S wrote:
...
My impression rfrom old books was that indexing as [i]arr was (is ?)
also legal.
If it had ever been legal, I would have expected it to be mentioned in
K&R 1st edition, in the section where it describes obsolete syntax that
used to be valid. It isn't.
It isn't mentioned there because the syntax isn't obsolete.
It's mentioned in K&R1 Appendix A section 14.3, page 210:
By definition, the subscript operator [] is interpreted in such a
way that E1 [E2] is identical to *((E1)+(E2)). Because of the
conversion rules which apply to +, if E1 is an array and E2 an
integer, then E1 [E2] refers to the E2-th member of E1. Therefore,
despite its asymmetric appearance, subscripting is a commutative
operation.
This is still true in all editions up to and including C23.
On 13/04/2025 15:54, Scott Lurndal wrote:
bart <bc@freeuk.com> writes:
On 13/04/2025 12:33, bart wrote:
Algol68 fits the role of systems language;
It somehow lost the word 'poorly'!
That would suprise Burroughs/Unisys, where the operating
system, database and utilites are all written in Algol.
Algol68 or Algol60? The former is very different.
[...]
[...]
for(let i = 1; i <= 36; i++) {
Is it that hard to provide a proper for-loop where you don't have to
spell out every single detail?
Fortran managed it in the 1950s!
On 4/13/25 15:14, Michael S wrote:
...
Yes, in practice it is the main reason why I find absence of
system-independent correspondence between [u]intn_t types and basic
integer types a PITA. But there exist few other cases where it causes
problems, e.g. using Intel intrinsic like _addcarry_u64() in code that
have to be compiled on different 64-bit OSes.
Well the basic integer types were intended to be system-specific, specifically to allow each implementation to choose whatever worked best
for the target platform. That's one of the features that helped ensure
that there's a fully conforming implementation of C for such a wide
variety of platforms. The size-named types came later, and it is of
course impossible for the correspondence between system-specific and size-named types to be system-independent.
On Sun, 13 Apr 2025 20:53:03 +0200
David Brown <david.brown@hesbynett.no> wrote:
On 13/04/2025 19:57, Michael S wrote:
On Fri, 11 Apr 2025 11:15:44 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
bart <bc@freeuk.com> writes:
[...]
8 A u64 type can be denoted as either 'uint64_t' OR as some
combination of the tokens (long, long, unsigned, [int])
"uint64_t" and "unsigned long long int" do not mean the same thing.
And it's a PITA.
There is only one thing I find a little bit annoying about the sized
integer types in C - the printf specifiers.
Yes, in practice it is the main reason why I find absence of system-independent correspondence between [u]intn_t types and basic
integer types a PITA. But there exist few other cases where it causes problems, e.g. using Intel intrinsic like _addcarry_u64() in code that
have to be compiled on different 64-bit OSes.
As to why you feel stronger than you about it, I'd guess it's because I
write code that has to be compiled, preferably without warnings, on
different platforms more often than you do. Most of 32-bit and 64-bit platforms are compatible to each other, but 64-bit Unix/Linus is at
odds with the rest of them.
On 13.04.2025 18:39, bart wrote:
[...]
for(let i = 1; i <= 36; i++) {
Is it that hard to provide a proper for-loop where you don't have to
spell out every single detail?
You mean like in Algol 68 or maybe Simula? (Both are interesting.)
Fortran managed it in the 1950s!
I obviously don't recall FORTRAN good enough to have memorized any
"good" feature. But as (mostly?) an anachronism it anyway doesn't
matter any more (to me).
WRT FORTRAN _loops_ I (faintly) only recall a syntax ambiguity "by
design" (and jump labels); certainly not something to advocate.
Janis
   do 100 i = a, b
       s1
       s2
       ...
100 continue
On 4/14/25 12:16, bart wrote:
    do 100 i = a, b
        s1
        s2
        ...
100 continue
    do i = a, b
       s1
       s2
    end do
Honestly, this is an old, known argument that I could never fully
understand. 'char' for characters, 'int' as a register sized entity,
'short' and 'long' as, say, additions. So far so good. "For a wide
variety of platforms" you cannot just use 'int' and hope that works
on 8, 16, or 32 bit processors the same way. Switching to 'long' or
'short' also doesn't provide any portability property since you've
no guarantee whether the necessary ranges can be represented with
them.
On 13.04.2025 18:48, bart wrote:
On 13/04/2025 15:54, Scott Lurndal wrote:
bart <bc@freeuk.com> writes:
On 13/04/2025 12:33, bart wrote:
Algol68 fits the role of systems language;
It somehow lost the word 'poorly'!
That would suprise Burroughs/Unisys, where the operating
system, database and utilites are all written in Algol.
Algol68 or Algol60? The former is very different.
I don't recall whether it was "Burroughs/Unisys" (that Scott mentioned)
but I know that there were systems programmed in Algol 68.
If you know Algol 60 you'd probably have recognized that it's unsuited
for systems programming (as opposed to Algol 68). - At least IMO.
On 13/04/2025 15:34, Kaz Kylheku wrote:
On 2025-04-13, bart <bc@freeuk.com> wrote:
On 13/04/2025 03:27, Janis Papanagnou wrote:
On 12.04.2025 13:00, bart wrote:
But I also 100% hate its syntax and various other bits and pieces. (OK, >>>>> about 80% then.)
(I also don't like its syntax too much. I think I'm just complaining
less than you about that. BTW, I've got the impression that all the
shortcomings of "C" are well known by most regulars here; they just
handle these facts in discussions differently than you.)
The shortcomings are downplayed considerably. Especially in discussions
involving me because they don't like it whenever someone states the obvious.
But also, most here have to use it professionally, so have learned to
work around it.
There are lots of examples of people just liking C.
C itself, or the things that C allowed you to do?
Well, given Knuth's own language was MIX (assembly for a made-up
machine), it is not surprising he prefers C.
C has spawned imitation in the form of "C like" languages, that all
started as grenfield projects that could have chosen any syntax
they wanted.
Some of this is to be expected: if they started off using brace syntax,
then their language will use braces. But some of the things they copy
are odd, like this for-loop from JS:
for(let i = 1; i <= 36; i++) {
Is it that hard to provide a proper for-loop where you don't have to
spell out every single detail? Fortran managed it in the 1950s!
On 2025-04-13, bart <bc@freeuk.com> wrote:
The first time I encountered a C for loop used for non-numbers
was a watershed moment for me. I rubbed my eyes once or twice.
"Wow, wait, you can do that?"
It might have been in the source code of an IRC client I was
compiling, where it had something like this:
for (node = list; node; node = node->next)
I realized, OMG, this is a great way of defining a for loop
construct. This is why for is the way it is.
So much better than the crap languages I used before which restricted a
dummy variable into going from one number to another.
That might have been the point after which I didn't look back.
Later I learned that much of the cool stuff around control flow
and expressions in C actually came from Lisp.
- Ternary if: (if test then else).
- Expressions having values, even assignments: (setq a (setq b (setq c 0)))
- Loops working with arbitrary data types.
No, it isn't, especially if you don't need once-only evaluation of the
range points:
#define for_range (type, var, from, to) \
for (type var = from; var <= to; var++)
Anyway, languages should be programmable so you're not stuck with
the loop that is built into the parser.
If I were to pick a non-C language for systems programming today, I
would take a serious look at Thomas Mertes' Seed 7, probably.
It lets you define new statement and such.
On 4/14/25 00:43, Janis Papanagnou wrote:
...
Honestly, this is an old, known argument that I could never fully
understand. 'char' for characters, 'int' as a register sized entity,
'short' and 'long' as, say, additions. So far so good. "For a wide
variety of platforms" you cannot just use 'int' and hope that works
on 8, 16, or 32 bit processors the same way. Switching to 'long' or
'short' also doesn't provide any portability property since you've
no guarantee whether the necessary ranges can be represented with
them.
Huh? There's guarantees for every one of those types.
Obviously, when interfacing with other software, I need to use the types
used in that interface. and that is the only context in which I would
use one of the exact-sized types.
Whenever I'm free to choose the type
of an integer variable, I normally prefer the fast size-named types,
unless storage space is an issue, in which case I use the least
size-named types.
The guarantees associated with the older types make
them roughly equivalent to the following size-named types:
[un]signed char [u]int_least8_t
[unsigned]short [u]int_least16_t
[unsigned]int [u]int_fast16_t
[unsigned]long [u]int_least32_t
[unsigned]long long [u]int_least64_t
Even before the size-named types came out, I always programmed with
those types as if they were the corresponding size-named types listed
above. Those types weren't ideal - too few of them can be described as corresponding to one of the fast size-named types. However, they were portable if used with due consideration of what guarantees went with
each type.
On 14.04.2025 15:00, James Kuyper wrote:
On 4/14/25 00:43, Janis Papanagnou wrote:
...
Honestly, this is an old, known argument that I could never fully
understand. 'char' for characters, 'int' as a register sized entity,
'short' and 'long' as, say, additions. So far so good. "For a wide
variety of platforms" you cannot just use 'int' and hope that works
on 8, 16, or 32 bit processors the same way. Switching to 'long' or
'short' also doesn't provide any portability property since you've
no guarantee whether the necessary ranges can be represented with
them.
Huh? There's guarantees for every one of those types.
Has that changed?
- I recall that there were only "compare to"
relations defined, like |short| <= |int| <= |long|
On 15/04/2025 00:12, Kaz Kylheku wrote:
On 2025-04-13, bart <bc@freeuk.com> wrote:
The first time I encountered a C for loop used for non-numbers
was a watershed moment for me. I rubbed my eyes once or twice.
I first time I saw this:
for(i=0; i<N; ++)
was such a moment for me. I thought what crappy syntax is that
On 14.04.2025 15:00, James Kuyper wrote:
On 4/14/25 00:43, Janis Papanagnou wrote:
...
Honestly, this is an old, known argument that I could never fully
understand. 'char' for characters, 'int' as a register sized entity,
'short' and 'long' as, say, additions. So far so good. "For a wide
variety of platforms" you cannot just use 'int' and hope that works
on 8, 16, or 32 bit processors the same way. Switching to 'long' or
'short' also doesn't provide any portability property since you've
no guarantee whether the necessary ranges can be represented with
them.
Huh? There's guarantees for every one of those types.
Has that changed?
... - I recall that there were only "compare to"
relations defined, like |short| <= |int| <= |long|
and there where systems where it was |short| == |int| == |long|
and other systems with |short| < |int| == |long|
or |short| < |int| < |long| or |short| == |int| < |long|
The guarantees associated with the older types make
them roughly equivalent to the following size-named types:
[un]signed char [u]int_least8_t
[unsigned]short [u]int_least16_t
[unsigned]int [u]int_fast16_t
[unsigned]long [u]int_least32_t
[unsigned]long long [u]int_least64_t
And that is where I have a different experience. - AFAICT, these
size equivalences were not a given.
Even before the size-named types came out, I always programmed with
those types as if they were the corresponding size-named types listed
above. Those types weren't ideal - too few of them can be described as
corresponding to one of the fast size-named types. However, they were
portable if used with due consideration of what guarantees went with
each type.
Was your programming focused to systems where the sizes were (by
accident) equal?
bart <bc@freeuk.com> writes:
On 15/04/2025 00:12, Kaz Kylheku wrote:
On 2025-04-13, bart <bc@freeuk.com> wrote:
The first time I encountered a C for loop used for non-numbers
was a watershed moment for me. I rubbed my eyes once or twice.
I first time I saw this:
for(i=0; i<N; ++)
was such a moment for me. I thought what crappy syntax is that
It's not correct syntax at all, and wouldn't compile, so yes,
it's is crappy syntax.
for(i = 0; i < N; i++)
on the other hand, is perfectly understandable and extremely
flexible.
There is no "import" or "export" in C - only "internal linkage" or
"external linkage" - file local or program global, if you prefer. The combinations "declare with external linkage but do not define" and
"declare with external linkage and define" are used to achieve import
and export of identifiers.
But its home module sees both of these, including the
'extern' version, but here 'abc' is exported!
Yes - "extern" does /not/ mean "export".
That is counter-intuitive: how can a module both import a name (via
'extern int') and export it (via 'int' without 'static')?
If the keyword "extern" were written "export", I'd agree on it being counter-intuitive. But it is not written that way. The point of
"extern" is that it indicates external linkage - program-wide sharing of
the identifier in question. It is shared amongst the units that exports
it (by defining it) and units that import it (by using it), usually
achieved by having the same shared header included by the exporting unit
and the importing units. This has a huge advantage compared to
languages where importing units read some kind of interface import file
but the exporting one does not - it is extremely easy in C to ensure
that all your shared identifiers match up correctly by keeping all
external declarations in shared headers and all definitions in C files.
On 15/04/2025 15:05, Scott Lurndal wrote:
What about this one:
for(i = 0; j < N; k++)
bart <bc@freeuk.com> writes:
On 15/04/2025 15:05, Scott Lurndal wrote:
What about this one:
for(i = 0; j < N; k++)
Any fool can write bad code in any language, including yours.
What do you think of this control block?
do
{
FILE f = fopen("file.txt", "r");
if (f == NULL) quit; /*goes to else part*/
/*success here*/
for (int i =0; i < 10; i++){
...
if (error) quit;
}
}
else
{
/*some error*/
}
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:
[...]
I withdraw my earlier statement. Please leave me out of any
future discussion of the subject.
Do you mean that your earlier statement was incorrect (i.e., that
the types are compatible), or do you merely wish to pretend you
never said anything without taking a position on whether they're
compatible, or do you refuse to say?
I am specifically _not_ saying either that my earlier statement
was right or that my earlier statement was wrong. My hope is
that henceforth people will act as though the statement never
entered the discussion. Does that clarify the matter for you?
That answers precisely what I was asking, thank you.
As often happens, I am mystified by your decision, but it is
unquestionably yours.
I'll try not to include you in any further discussion, but I do
not promise to try very hard.
bart <bc@freeuk.com> writes:
[...]
Someone, not anyone but the all-knowing Tim, said: "and those types
are not compatible, because the two struct tags are different."
Do you agree with that? Or is there something more to making two types
be incompatible?
I don't recall the exact discussion and I wouldn't try to speak
for Tim, but I suspect he was saying that the fact that the two
struct tags are different is enough to know that the types are
not compatible. [...]
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
bart <bc@freeuk.com> writes:
[...]
Someone, not anyone but the all-knowing Tim, said: "and those types
are not compatible, because the two struct tags are different."
Do you agree with that? Or is there something more to making two types >>>> be incompatible?
I don't recall the exact discussion and I wouldn't try to speak
for Tim, but I suspect he was saying that the fact that the two
struct tags are different is enough to know that the types are
not compatible. [...]
Considering the circumstances, rather than focusing on what I
(may have) meant, it seems better to focus on what is true,
whether I meant it or not.
Feel free to do so, rather than resurrecting a post from nearly a
month ago to criticize me for what I chose to focus on
and adding nothing to the actual discussion.
The discussion died out weeks ago. Why would you resurrect it?
Em 4/4/2025 5:48 PM, Tim Rentsch escreveu:
Thiago Adams <thiago.adams@gmail.com> writes:
  What do you think of this control block?
  do
  {
     FILE f = fopen("file.txt", "r");
     if (f == NULL) quit; /*goes to else part*/
     /*success here*/
     for (int i =0; i < 10; i++){
         ...
         if (error) quit;
     }
  }
  else
  {
     /*some error*/
  }
I think it doesn't belong in comp.lang.c.
I also think you have been participating in comp.lang.c
long enough to know better. Kindly take your language
fantasies somewhere else.
I think the only reason you're saying that is because it's not
implemented in GCC, Clang, or maybe even MSVC. I've never seen you
complain about any GCC extensions here.
I think Thiago's idea is brilliant. He should become a
member of the standardization committee. He's welcome
to post suggestions like this here.
On 07/05/2025 05:56, Wuns Haerst wrote:
I think Thiago's idea is brilliant. He should become a
member of the standardization committee. He's welcome
to post suggestions like this here.
Irony is always dangerous. Prepare for incoming.
I think Thiago's idea is brilliant. He should become a
member of the standardization committee. He's welcome
to post suggestions like this here.
Am 10.04.2025 um 00:07 schrieb Tim Rentsch:
When someone is responding to a post, they are responding ONLY to
the content in the posting they are responing to;Â not to some
earlier posting in the same thread, not to a different posting
submitted two weeks ago, not to what you meant to say but didn't,
not to thoughts in your head but that you didn't say, but ONLY TO
WHAT IS SAID IN THE POSTING BEING RESPONDED TO.
If you can learn to follow this simple rule everyone in the
newsgroup will be better off, including you.
You're constantly overwhelmed by what people write here. Both in
terms of content and the nature of the discussion. Don't try to
constantly set rules; that seems petty.
Am 06.04.2025 um 17:14 schrieb Tim Rentsch:
My impression was that "defer", or something very much like
it, is being considered for inclusion in a future C standard. ...
With C++ you can have defer without extending the language.
Am 06.04.2025 um 17:14 schrieb Tim Rentsch:
My impression was that "defer", or something very much like
it, is being considered for inclusion in a future C standard. ...
With C++ you can have defer without extending the language.
Am 09.05.2025 um 16:38 schrieb Richard Heathfield:
Tim's not setting a draconian rule in stone. He's presenting a
perfectly sensible rule of thumb that is based on his decades of
experience of posting to this group. ...
No, he's just annoyed. It is perfectly normal to
go from one topic to another in such a deep thread
Am 09.05.2025 um 17:01 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 06.04.2025 um 17:14 schrieb Tim Rentsch:
My impression was that "defer", or something very much like
it, is being considered for inclusion in a future C standard.
...
With C++ you can have defer without extending the language.
This, however is comp.lang.c.
I'm just trying to make it clear that C lacks convenience
and productivity on every level.
C folks simply don't want
to abandon their minimalism paradigm, which continues to
make the language very difficult to use.
On 09/05/2025 16:04, Bonita Montero wrote:
Am 09.05.2025 um 17:01 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 06.04.2025 um 17:14 schrieb Tim Rentsch:
My impression was that "defer", or something very much like
it, is being considered for inclusion in a future C standard. ...
With C++ you can have defer without extending the language.
This, however is comp.lang.c.
I'm just trying to make it clear that C lacks convenience
and productivity on every level.
Then use something convenient and productive. But please confine your discussions of your chosen alternative to
comp.lang.your.chosen.alternative instead of dragging them into
comp.lang.c, where we discuss C.
C folks simply don't want
to abandon their minimalism paradigm, which continues to
make the language very difficult to use.
Then do by all means use something easier. But please confine your discussions of your chosen alternative to
comp.lang.your.chosen.alternative instead of dragging them into
comp.lang.c, where we discuss C.
[...]
On 09/05/2025 16:54, Janis Papanagnou wrote:
<snip>
Since some folks feel comfortable in their "C" bubble I understand
that these people might feel annoyed by such posts.
Each newsgroup has a topic. I subscribe to no fewer than ten
newsgroups, because I am interested in those ten topics. If you
are interested in C++, you can subscribe to comp.lang.c++ and
chat about it all day long and nobody will bat an eyelid. I have
no doubt that many comp.lang.c subscribers are also subscribed to >comp.lang.c++. Why not join their number, and keep the salt in
the salt pot and the pepper in the pepper pot?
But showing deficiencies (in "C") and providing counter-examples or
alternatives from other languages [as done here] should be welcome.
Why?
Four important ways that C scores over other languages are:
* Speed
* Simplicity
* Size
* Portability
The more you add, the more likely you are to slow it down, the
more complex you make it, the bigger it gets, and the harder it
is to port.
Since some folks feel comfortable in their "C" bubble I understand
that these people might feel annoyed by such posts.
But showing deficiencies (in "C") and providing counter-examples or alternatives from other languages [as done here] should be welcome.
But of course no one forces these annoyed people to read all posts; suggestions had already been given to just skip those inconvenient
threads or subhreads.
On 09.05.2025 17:26, Richard Heathfield wrote:
On 09/05/2025 16:04, Bonita Montero wrote:
Am 09.05.2025 um 17:01 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 06.04.2025 um 17:14 schrieb Tim Rentsch:
My impression was that "defer", or something very much like
it, is being considered for inclusion in a future C standard. ...
With C++ you can have defer without extending the language.
This, however is comp.lang.c.
I'm just trying to make it clear that C lacks convenience
and productivity on every level.
Then use something convenient and productive. But please confine your
discussions of your chosen alternative to
comp.lang.your.chosen.alternative instead of dragging them into
comp.lang.c, where we discuss C.
C folks simply don't want
to abandon their minimalism paradigm, which continues to
make the language very difficult to use.
Then do by all means use something easier. But please confine your
discussions of your chosen alternative to
comp.lang.your.chosen.alternative instead of dragging them into
comp.lang.c, where we discuss C.
(That post sounds and is written like a mantra. Gee!)
Since some folks feel comfortable in their "C" bubble I understand
that these people might feel annoyed by such posts.
But showing deficiencies (in "C") and providing counter-examples or alternatives from other languages [as done here] should be welcome.
(IMO. YMMV, of course.)
Am 09.05.2025 um 19:09 schrieb David Brown:
4. Everyone familiar with or interested in C++ will already know that
you can make a "defer" feature in C++. Any reasonably competent C++
programmer could make such a template class.
The defer-class is rather simple, but the xdefer-class is rather tricky because it is a concatenation of structures of different types.
Richard Heathfield <rjh@cpax.org.uk> writes:
Four important ways that C scores over other languages are:
* Speed
* Simplicity
* Size
* Portability
The more you add, the more likely you are to slow it down, the
more complex you make it, the bigger it gets, and the harder it
is to port.
To be fair to C++ (not to C++ fanatics, however), it is
worth pointing out that one doesn't need to use all the
C++ crapola to leverage some of the good features of
C++ (C with classes, basically) and obtain the same four
important characteristics you raise above.
Am 09.05.2025 um 18:26 schrieb Richard Heathfield:
* Speed
* Simplicity
* Size
* Portability
The same can be said about C++, but the simplicity in C++
is on a different level.
Am 09.05.2025 um 20:11 schrieb Richard Heathfield:
I have classes at my fingertips whenever I want them, I don't
have to wait 20 years for the ISO guys to change C, and C gets
to stay light and tight.
With C the language is light and compact, with C++ the written
code is light and compact.
On Fri, 11 Apr 2025 17:22:37 -0000 (UTC)
Kaz Kylheku <643-408-1753@kylheku.com> wrote:
On 2025-04-11, Michael S <already5chosen@yahoo.com> wrote:
On Thu, 10 Apr 2025 17:59:15 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
An understanding of what "compatible types" means.
Bart didn't say that types are compatible or non-compatible.
He said that they are 'compatible enough'. That is not terminology
of C Standard, but terminology of his own. And he seems to
understand it.
In my own translation, 'compatible enough' means that when these
structs are accessed then any sane or even semi-sane compiler will
generate code that will have the same effect as in case of access
through structures with literally identical declarations.
so struct { long x; } and struct { int x; } are compatible enough,
in situations that are portable enough.
I wish they would be, but according to C Standard they are not,
ene when both represent 32-bt signed integer. That's because of
misfeature called 'strong aliasing rules'.
IMO, C would become better without this misfeature.
[...]
Read what people write, not what you think they meant.
Michael S <already5chosen@yahoo.com> writes:
On Fri, 11 Apr 2025 17:22:37 -0000 (UTC)
Kaz Kylheku <643-408-1753@kylheku.com> wrote:
On 2025-04-11, Michael S <already5chosen@yahoo.com> wrote:
On Thu, 10 Apr 2025 17:59:15 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
An understanding of what "compatible types" means.
Bart didn't say that types are compatible or non-compatible.
He said that they are 'compatible enough'. That is not terminology
of C Standard, but terminology of his own. And he seems to
understand it.
In my own translation, 'compatible enough' means that when these
structs are accessed then any sane or even semi-sane compiler will
generate code that will have the same effect as in case of access
through structures with literally identical declarations.
so struct { long x; } and struct { int x; } are compatible enough,
in situations that are portable enough.
I wish they would be, but according to C Standard they are not,
ene when both represent 32-bt signed integer. That's because of
misfeature called 'strong aliasing rules'.
IMO, C would become better without this misfeature.
I think this reaction is rather shortsighted. Making this change
would incur several downsides, and offers no significant upside
that I can see.
First it would greatly complicate the language semantics.
Whether a program is meaningful, and if so what the meaning is,
would be much harder to state than it is now.
Second it would imply that whether a program is well-defined is a
lot more dependent on implementation-specific choices than it is
now.
Third, as a consequence of that, it would be harder to write
program verification tools, because they would need to take these
more extensive implementation dependencies into consideration.
Fourth, there would be consequences for program optimization, and
it is hard to dismiss those. Some people may not care about the optimizations losses, but certainly many people want the benefits
of those optimizations.
Fifth, related to the previous point, as a practical matter it would
make getting the optimization benefits back again be nearly
impossible. As things are now, it's easy to have a compiler option
to disable the consequences of strong typing rules, and the result
can still be a conforming implementation. But if the C standard
would prescribe the semantics of cross-type access, then any option
to ignore the implications of that prescription would necessarily
make using said option result in a non-conforming implementation.
To say the last point another way, with things as they are now
developers can choose whether they want to observe the cross-type
access restrictions, or ignore them, and still get a C compiler.
If the effective type rules were discarded, there is no way to
choose the more-optimizing path without getting something that
is not a C compiler.
Given that you can always get what you want either by choosing
an appropriate compiler option (if available) or by using one of
the well-known legal workarounds, I think it's hard to make a
case that getting rid of the effective type restrictions is a
good idea.
On 09.05.2025 17:26, Richard Heathfield wrote:
On 09/05/2025 16:04, Bonita Montero wrote:
Am 09.05.2025 um 17:01 schrieb Scott Lurndal:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 06.04.2025 um 17:14 schrieb Tim Rentsch:
My impression was that "defer", or something very much like
it, is being considered for inclusion in a future C standard. ...
With C++ you can have defer without extending the language.
This, however is comp.lang.c.
I'm just trying to make it clear that C lacks convenience
and productivity on every level.
Then use something convenient and productive. But please confine your
discussions of your chosen alternative to
comp.lang.your.chosen.alternative instead of dragging them into
comp.lang.c, where we discuss C.
Since some folks feel comfortable in their "C" bubble I understand
that these people might feel annoyed by such posts.
But showing deficiencies (in "C") and providing counter-examples or alternatives from other languages [as done here] should be welcome.
(IMO. YMMV, of course.) [...]
But of course no one forces these annoyed people to read all posts; suggestions had already been given to just skip those inconvenient
threads or subhreads.
David Brown <david.brown@hesbynett.no> writes:
[...]
For plain integer types, however, I think the argument for making
equal-sized types compatible is a lot stronger. Some compilers
specifically say that they allow aliasing between such types (MSVC,
according to what I have read, have said they never intend to support
"strict aliasing" optimisations). Many software projects (such as
Linux) use "-fno-strict-aliasing". And countless C programmers
mistakenly believe that identically sized integer types are compatible
(though I am not advocating for a weaker language simply because some
users misunderstand the rules).
I think that a lot of C programmers misunderstand what "compatible
types" means. Many seem to think that two types are compatible if
they have the same representation and can be assigned without a cast.
In fact type compatibility is a much stricter concept than that.
Two types are compatible if they are *the same type*, and in a few
other circumstances. For example, char, signed char, and unsigned
char are all incompatible with each other, even though two of them
are guaranteed to have the same representation.
A good way to think about it is that pointers to two types can be
assigned without a cast if and only if the two types are compatible.
For example, int and long objects can be assigned to each other
without a cast, but int* and long* objects cannot.
And changing the language to make int and long conditionally
compatible would (a) make it too easy to write code that's valid
in one implementation but violates a constraint in another, and (b)
would break existing code.
For example, a generic selection cannot
have two associations with compatible types. _Generic with "int:"
and "long:" would become invalid for implementations that make int
and long compatible.
(I wouldn't mind seeing a new form of generic association that
selects the *first* matching type, but that's another can of worms.)
On 09/05/2025 17:54, Janis Papanagnou wrote:
[...]
Comparisons between C and other languages can certainly be on-topic for
a C group. And deficiencies of C are as topical as the language's good points.
However, Bonita's post here - like almost all Bonita's posts in this
group - are not helpful or topical, but merely trolls of "C++ is vastly better than C - look at this line noise to see what you can do in C++".
Consider this about Bonita's post :
[ farraginous list snipped ]
(Note: I'm not saying that the previous post's content is correct,
just that it was obviously meant as an improvement, which could or
not affect evolution of "C" if considered; a point for discussion
[for those who think it's worth].)
It is not at all surprising that people find Bonita's posts in
comp.lang.c annoying, and would be happier if they were restricted to comp.lang.c++. Most people just ignore them, others use killfiles, and
some people optimistically try to persuade Bonita not to write such
posts. I'd be surprised if there was anyone who actually thought they
were a positive contribution to the group.
As a general principle, I agree with you that languages other than C can
at times be relevant and interesting in this group - but in this
specific case, I see no value in Bonita's post.
[...]
But of course no one forces these annoyed people to read all posts;
suggestions had already been given to just skip those inconvenient
threads or subhreads.
This comment sounds like hearing from a neighbor that I shouldn't
mind if his dog shits on my lawn, because I can easily step over
the shit.
Except that here there is a notable difference, in
that it isn't the dog but the dog's owner doing the shitting.
On 09/05/2025 16:54, Janis Papanagnou wrote:
<snip>
Since some folks feel comfortable in their "C" bubble I understand
that these people might feel annoyed by such posts.
Each newsgroup has a topic. I subscribe to no fewer than ten newsgroups, because I am interested in those ten topics. If you are interested in
C++, you can subscribe to comp.lang.c++ and chat about it all day long
and nobody will bat an eyelid. I have no doubt that many comp.lang.c subscribers are also subscribed to comp.lang.c++. Why not join their
number, and keep the salt in the salt pot and the pepper in the pepper pot?
But showing deficiencies (in "C") and providing counter-examples or
alternatives from other languages [as done here] should be welcome.
Why?
Four important ways that C scores over other languages are:
* Speed
* Simplicity
* Size
* Portability
The more you add, the more likely you are to slow it down, the more
complex you make it, the bigger it gets, and the harder it is to port.
[...]
On 09.05.2025 18:26, Richard Heathfield wrote:
On 09/05/2025 16:54, Janis Papanagnou wrote:
<snip>
Since some folks feel comfortable in their "C" bubble I understand
that these people might feel annoyed by such posts.
Each newsgroup has a topic. I subscribe to no fewer than ten newsgroups,
because I am interested in those ten topics. If you are interested in
C++, you can subscribe to comp.lang.c++ and chat about it all day long
and nobody will bat an eyelid. I have no doubt that many comp.lang.c
subscribers are also subscribed to comp.lang.c++. Why not join their
number, and keep the salt in the salt pot and the pepper in the pepper pot?
(You seem to have missed the point; see below.)
But showing deficiencies (in "C") and providing counter-examples or
alternatives from other languages [as done here] should be welcome.
Why?
Four important ways that C scores over other languages are:
* Speed
* Simplicity
* Size
* Portability
The more you add, the more likely you are to slow it down, the more
complex you make it, the bigger it gets, and the harder it is to port.
See; now you're discussing
(in a very principle way) why the other
poster's suggestion makes no sense [to you]. - That was the point.
(And you can always skip questions or suggestions or discussions
you are not interested in.)
On 09.05.2025 19:09, David Brown wrote:
On 09/05/2025 17:54, Janis Papanagnou wrote:
[...]
Comparisons between C and other languages can certainly be on-topic for
a C group. And deficiencies of C are as topical as the language's good
points.
However, Bonita's post here - like almost all Bonita's posts in this
group - are not helpful or topical, but merely trolls of "C++ is vastly
better than C - look at this line noise to see what you can do in C++".
Yes, I understand your dislike. And in this case it's specifically easy
for folks who dislike specific persons or dislike what they say what
they can or should do about that. (And below in your post you formulate
some personal options one may take to not see those people or their contributions any more.)
Consider this about Bonita's post :
[ farraginous list snipped ]
Sure. - But there was no need to analyze or list all that (for me at
least); you may have noticed my statement (and read between the lines;
if it's not obvious I may have formulated that better, I admit.)
I think with a good grain of serenity we could also spare us those
longish threads. Let's individually pick and choose what we like.
On 12.05.2025 20:44, Tim Rentsch wrote:
[...]
But of course no one forces these annoyed people to read all posts;
suggestions had already been given to just skip those inconvenient
threads or subhreads.
This comment sounds like hearing from a neighbor that I shouldn't
mind if his dog shits on my lawn, because I can easily step over
the shit.
This comparison says, unfortunately, a lot more about you than
about anything else.
It was a while back now, but there was a time when I lobbied in this
group for a slight relaxing of topicality rules - not by breaching those rules, but by inviting discussion, cavassing opinions, and collating
them into a show of hands. By an overwhelming majority the group turned
me down. I didn't tell them 'to hell with you, I'll discuss what I damn
well want to, and if you don't like it, tough cheese'; I accepted the
group's decision.
There may well be some subscribers here who remember that discussion and might be prepared to corroborate the above.
On 12/05/2025 22:25, Keith Thompson wrote:...
I think that a lot of C programmers misunderstand what "compatible
types" means. Many seem to think that two types are compatible if
they have the same representation and can be assigned without a cast.
Yes. Basically, most C programmers are not particularly aware of the technical definitions of some of the terms in C standards where they
differ from common usage. The word "compatible" in English means that
the things in question can work together or fit together.
On 5/13/25 05:40, David Brown wrote:
On 12/05/2025 22:25, Keith Thompson wrote:
...
I think that a lot of C programmers misunderstand what "compatible
types" means. Many seem to think that two types are compatible if
they have the same representation and can be assigned without a cast.
Yes. Basically, most C programmers are not particularly aware of the
technical definitions of some of the terms in C standards where they
differ from common usage. The word "compatible" in English means that
the things in question can work together or fit together.
That's pretty much what it means in C. Two C types are compatible
in C if the C standard *guarantees* that they can work together -
that you can use the types interchangeably. [...]
James Kuyper <jameskuyper@alumni.caltech.edu> writes:...
On 5/13/25 05:40, David Brown wrote:
Yes. Basically, most C programmers are not particularly aware of the
technical definitions of some of the terms in C standards where they
differ from common usage. The word "compatible" in English means that
the things in question can work together or fit together.
That's pretty much what it means in C. Two C types are compatible in C
if the C standard *guarantees* that they can work together - that you
can use the types interchangeably. The tricky part is the definition of
which pairs of types the C standard makes those guarantees for.
The key point is that the undefined behavior of code which treats
incompatible types as if they were compatible could also be that they
work together, too, depending upon the implementation.
I suggest that the phrase "work together" is too vague.
On 09/05/2025 15:25, Bonita Montero wrote:
Am 10.04.2025 um 00:07 schrieb Tim Rentsch:
When someone is responding to a post, they are responding ONLY to
the content in the posting they are responing to; not to some
earlier posting in the same thread, not to a different posting
submitted two weeks ago, not to what you meant to say but didn't,
not to thoughts in your head but that you didn't say, but ONLY TO
WHAT IS SAID IN THE POSTING BEING RESPONDED TO.
If you can learn to follow this simple rule everyone in the
newsgroup will be better off, including you.
You're constantly overwhelmed by what people write here. Both in
terms of content and the nature of the discussion. Don't try to
constantly set rules; that seems petty.
Tim's not setting a draconian rule in stone. He's presenting a
perfectly sensible rule of thumb that is based on his decades of
experience of posting to this group. Usenet works best when you snip
the bits you're not replying to, and reply only within the context you
have retained. Nearly all the leading experts in this group nearly
always observe this rule of thumb, because it's simple common sense so
to do.
On what basis do you justify laying down your law for Tim to follow?
On 5/13/25 20:51, Keith Thompson wrote:
James Kuyper <jameskuyper@alumni.caltech.edu> writes:...
On 5/13/25 05:40, David Brown wrote:
Yes. Basically, most C programmers are not particularly aware of the
technical definitions of some of the terms in C standards where they
differ from common usage. The word "compatible" in English means that
the things in question can work together or fit together.
That's pretty much what it means in C. Two C types are compatible in C
if the C standard *guarantees* that they can work together - that you
can use the types interchangeably. The tricky part is the definition of
which pairs of types the C standard makes those guarantees for.
The key point is that the undefined behavior of code which treats
incompatible types as if they were compatible could also be that they
work together, too, depending upon the implementation.
I suggest that the phrase "work together" is too vague.
I was trying to match the wording of the text I was responding to. What
I meant can be made far more precise: the C standard guarantees that two compatible types will work together, in the sense that every case where
the C standard mandates that two types must be compatible in order for something to work, it will work for them.
On 13/05/2025 14:54, Janis Papanagnou wrote:
[...]
I think with a good grain of serenity we could also spare us those
longish threads. Let's individually pick and choose what we like.
No, let's not. Let's - at least occasionally - take some responsibility
and not ignore inappropriate behaviour. I don't want to drag this out,
or overreact - Bonita's posts are not /that/ bad. But be clear on this:
it was not Richard's post berating Bonita that made a long thread branch about topicality, it was /your/ post complaining about his post.
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
On 5/13/25 05:40, David Brown wrote:
On 12/05/2025 22:25, Keith Thompson wrote:...
I think that a lot of C programmers misunderstand what "compatible
types" means. Many seem to think that two types are compatible if
they have the same representation and can be assigned without a cast.
Yes. Basically, most C programmers are not particularly aware of the
technical definitions of some of the terms in C standards where they
differ from common usage. The word "compatible" in English means that
the things in question can work together or fit together.
That's pretty much what it means in C. Two C types are compatible in C
if the C standard *guarantees* that they can work together - that you
can use the types interchangeably. The tricky part is the definition of
which pairs of types the C standard makes those guarantees for.
The key point is that the undefined behavior of code which treats
incompatible types as if they were compatible could also be that they
work together, too, depending upon the implementation.
I suggest that the phrase "work together" is too vague. It's
perfectly reasonable to say that two types that can be assigned to
each other without casts can "work together", and I might even call
them "compatible" if the standard didn't already define the term.
To a first approximation, two types are compatible if they're the
same type. The standard's section on compatible types points to
additional rules for some cases. IMHO the English word "compatible"
suggests a much looser relationship, but we're stuck with the
standard's terminology (and I'm not sure what would be better).
On 13/05/2025 13:55, Janis Papanagnou wrote:
(And you can always skip questions or suggestions or discussions
you are not interested in.)
And if someone urinates in your beer, you can always spit it out, right?
[...]
On 13/05/2025 14:13, Janis Papanagnou wrote:
On 12.05.2025 20:44, Tim Rentsch wrote:
[...]
But of course no one forces these annoyed people to read all posts;
suggestions had already been given to just skip those inconvenient
threads or subhreads.
This comment sounds like hearing from a neighbor that I shouldn't
mind if his dog shits on my lawn, because I can easily step over
the shit.
This comparison says, unfortunately, a lot more about you than
about anything else.
On the contrary, it says a lot more about you who choose to put your own agenda above the group dynamic because other people's opinions don't
matter to you.
[...]
Nobody can stop you posting whatever the hell you like here... except
you. So the question comes down to whether you are an adult with the
capacity for self-control and the will to participate in a way that
observes the customs of the people whose company you have sought, or
whether you are just a spoiled teenager in an adult's body.
The choice is entirely yours.
On 13.05.2025 15:35, Richard Heathfield wrote:
On 13/05/2025 13:55, Janis Papanagnou wrote:
(And you can always skip questions or suggestions or discussions
you are not interested in.)
And if someone urinates in your beer, you can always spit it out, right?
You seem to like (as Tim in another post) disgusting, inappropriate and misleading comparisons.
On 13.05.2025 15:46, Richard Heathfield wrote:
On 13/05/2025 14:13, Janis Papanagnou wrote:
On 12.05.2025 20:44, Tim Rentsch wrote:
[...]
But of course no one forces these annoyed people to read all posts;
suggestions had already been given to just skip those inconvenient
threads or subhreads.
This comment sounds like hearing from a neighbor that I shouldn't
mind if his dog shits on my lawn, because I can easily step over
the shit.
This comparison says, unfortunately, a lot more about you than
about anything else.
On the contrary, it says a lot more about you who choose to put your own
agenda above the group dynamic because other people's opinions don't
matter to you.
I have no agenda
On 14/05/2025 04:23, James Kuyper wrote:
On 5/13/25 20:51, Keith Thompson wrote:
James Kuyper <jameskuyper@alumni.caltech.edu> writes:...
On 5/13/25 05:40, David Brown wrote:
Yes. Basically, most C programmers are not particularly aware of the >>>>> technical definitions of some of the terms in C standards where they >>>>> differ from common usage. The word "compatible" in English means that >>>>> the things in question can work together or fit together.
That's pretty much what it means in C. Two C types are compatible in C >>>> if the C standard *guarantees* that they can work together - that you
can use the types interchangeably. The tricky part is the definition of >>>> which pairs of types the C standard makes those guarantees for.
The key point is that the undefined behavior of code which treats
incompatible types as if they were compatible could also be that they
work together, too, depending upon the implementation.
I suggest that the phrase "work together" is too vague.
I was trying to match the wording of the text I was responding to. What
I meant can be made far more precise: the C standard guarantees that two
compatible types will work together, in the sense that every case where
the C standard mandates that two types must be compatible in order for
something to work, it will work for them.
That's a tautology - the C standard guarantees that two compatible types
will work together in situations where the C standard requires that the
types are compatible.
On 14/05/2025 04:23, James Kuyper wrote:...
I was trying to match the wording of the text I was responding to. What
I meant can be made far more precise: the C standard guarantees that two
compatible types will work together, in the sense that every case where
the C standard mandates that two types must be compatible in order for
something to work, it will work for them.
That's a tautology - the C standard guarantees that two compatible
types will work together in situations where the C standard requires
that the types are compatible.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 546 |
Nodes: | 16 (2 / 14) |
Uptime: | 146:25:10 |
Calls: | 10,383 |
Calls today: | 8 |
Files: | 14,054 |
D/L today: |
2 files (1,861K bytes) |
Messages: | 6,417,708 |