simple question about inter modular acces

G

glen herrmannsfeldt

Keith Thompson said:
The only references to implementation-specific capacity limits that
I can find in N1570 are:
Section 1, paragraph 2:
This International Standard does not specify
[...]
- the size or complexity of a program and its data that will
exceed the capacity of any specific data-processing system
or the capacity of a particular processor
and section 5.2.4.1, which discusses translation limits and has
the long list of things like "127 nesting levels of blocks".
What you're suggesting, if I understand correctly, is that an
implementation could accept a declaration of a structure containing
function pointers, bit fields, and 42 levels of nested unions, but
reject a declaration "float x;" because it exceeds its capacity,
and claim conformance to the standard. Is my understanding of your
position correct?

On a machine without floating point hardware, it would be done
in software. If the routines to do it took more memory than available
on the system, it would technically "exceed the capacity".

(Might be true on the 4004 and 8048.)

Now, the compiler could compile the calls to the software floating
point, but since it didn't fit in memory, they will never be called.

Might as well not write them in the first place.
I suppose that's true in the most literal sense, but I don't believe
the standard as written is *intended* to make floating-point an
optional feature. By your reasoning, a compiler could refuse to
accept *any* arbitrary language feature as long as it issues a
diagnostic and justifies that rejection as a capacity limitation
(regardless of how the diagnostic is phrased).
I don't believe the permission to impose capacity limits is intended
to permit omitting entire non-optional features.

I suppose they didn't think about machines that small. K&R might
have, though.
To take things just a little further, I could construct a single C
program that precisely hits every one of the translation limits in
5.2.4.1 and produces no output or other visible behavior. I could
then write a "compiler" that recognizes that single program and
creates an executable that does nothing, while rejecting every other
C source file. I would then have a conforming C implementation
according to the letter of the standard -- but it would be utterly
useless.

Yes. Might as well not write it then.

-- glen
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Keith Thompson said:
[...]
I understand your thesis here, but you still haven't presented
any convincing evidence that it's correct. Any device for
which a conforming C compiler cannot be fairly easily provided
is so limited (or perhaps unorthodox) that a suitable language
for it would not be C-like except perhaps very superficially.

I think this may be the fundamental point on which we disagree.

I haven't worked on very small embedded systems, but I can
imagine a system (again, an 8051 or 4004 might qualify) where it
makes perfectly good sense to implement all C syntax and
semantics *except* that, say, floating-point types and integers
wider than 16 bits are not supported.

This can be done in a conforming implementation, as I have
already explained.
[...]

An implementation that has no support for floating-point, for a
target system on which such support would not be useful, can be
"conforming" only in some sense that is practically
indistinguishable from non-conformance.

I'm not sure why you put quotes around the word conforming, since
I am using the word in the same sense that the Standard defines
it. More importantly the phrasing used disguises the distinction
I am trying to highlight: the key question is not whether an
implmentation is conforming -- which might be true purely by
accident -- but whether its implementtors are committed to
delivering a conforming implementation. Continued below...

The only references to implementation-specific capacity limits
that I can find in N1570 are:

Section 1, paragraph 2:

This International Standard does not specify
[...]
- the size or complexity of a program and its data that will
exceed the capacity of any specific data-processing system
or the capacity of a particular processor

and section 5.2.4.1, which discusses translation limits and has
the long list of things like "127 nesting levels of blocks".

What you're suggesting, if I understand correctly, is that an
implementation could accept a declaration of a structure containing
function pointers, bit fields, and 42 levels of nested unions, but
reject a declaration "float x;" because it exceeds its capacity,
and claim conformance to the standard. Is my understanding of your
position correct?

No, I wasn't considering section 1 paragraph 2. More below.
I suppose that's true in the most literal sense, but I don't believe
the standard as written is *intended* to make floating-point an
optional feature. By your reasoning, a compiler could refuse to
accept *any* arbitrary language feature as long as it issues a
diagnostic and justifies that rejection as a capacity limitation
(regardless of how the diagnostic is phrased).

I don't believe the permission to impose capacity limits is
intended to permit omitting entire non-optional features.

My remarks are about the letter of the Standard, not its intent.
Furthermore I don't the Standard signals any clear intent in this
regard, so going by the letter is pretty much the only option
available.
To take things just a little further, I could construct a single
C program that precisely hits every one of the translation limits
in 5.2n.4.1 and produces no output or other visible behavior. I
could then write a "compiler" that recognizes that single program
and creates an executable that does nothing, while rejecting
every other C source file. I would then have a conforming C
implementation according to the letter of the standard -- but it
would be utterly useless.

I'm not sure I completely agree with your conclusion, but even if
I did it wouldn't change what I'm saying. The Standard admits
any number of behaviors in conforming implementations that are
utterly useless.
(I believe the intent of 5.2.4.1 is that any *reasonable*
compiler that accepts that "one program" will also accept most
real-world code; the easiest way to satisfy 5.2.4.1 while
implementing a useful compiler is to avoid imposing any fixed
limits at all, which is what most vendors have actually done.)

This comment glosses over an important distinction, namely,
the difference between "accept" and "translate and execute".
Conforming implementations are required to "translate and
execute" only one program, but they are required to "accept"
any strictly conforming program. Any implementation may
choose not to accept a program having a declaration

char foo[ 65536 ];

because the program is not strictly conforming. However, a
conforming hosted implementation must accept the following
program

#include <stdio.h>
char small_foo[ 32767 ];
int main( void ){ return 0; }

(even if it doesn't translate and execute it) because the program
is strictly conforming when considered in a hosted environment.
This program may be accepted by a conforming freestanding
implementation, but it need not be, because of the inclusion of a
system header <stdio.h>. Now how about the same program but
without the #include line:

char small_foo[ 32767 ];
int main( void ){ return 0; }

I would argue that a conforming freestanding implementation is
not obliged to accept this program, because it is not strictly
conforming when considered in a freestanding environment.
Certainly the Standard anticipates results of this kind, because
it specifically designates the limit on minimum object size given
in 5.2.4.1 p1 as applying to "hosted implementations only".
Furthermore this result coincides with an intuitive sense of what
"freestanding" means, namely, for minimal environments. How
minimal is minimal? Pointedly, the Standard doesn't say. So
even though carrying that reasoning down to very small sizes
might be unexpected, I don't think it is contrary to the spirit
of the notion that freestanding implementations may be "tiny", so
be prepared to accept them as such.

Incidentally, considering the cited portion in 1 p2, note that a
conforming implementation could /accept/ a program that uses
floating point but not /translate and execute/ said program,
citing a capacity limit. Such an implementation clearly conforms
to the letter of what constitutes a conforming implementation,
and considering 1 p2 I believe it conforms to the spirit as well.

Yes, I *think* the Standard allows such behavior, but I hardly
think that's the only *relevant* question.

What I meant was relevant to the point under discussion, which is
concerned only with whether certain implementations are
conforming.
And I'm not
completely convinced that the Standard actually allows it. The
counterargument would be that failing to implement floating-point
does not constitute a *capacity* limitation as permitted by 1p2.

Not a compelling argument. Clearly there are existing hardware
targets having memory limitations severe enough so that
implementing even a single floating-point operation exceeds the
capacity of program memory. But the same model processor with
more memory might have enough room for floating-point operation
subroutines.
How is it impossible to answer? I believe a single compiler
could simultaneously meet either description, with the only
difference being how it's described.

Two problems: one, what is meant by the terms isn't clear; two,
there are two implementations, but what is different between
them isn't specified. Apparently your intention was to ask
about the phrases applied to the same (unknown) implementation,
but the way the question was asked that wasn't clear.
Suppose we have two groups of implementors, A and B. Group A has
decided to do a conforming implementation. Group B has decided
to implement "C-", which is most of C but leaves out some things
that they feel would impact the implementation too much, such as
floating point and 'long long'. The implementation of group A is
conforming working under the assumption of the thesis posited
above. The implementation of group B might or might not be
conforming under the same conditions.

Given this state of affairs, what do we know? About the
implementation done by group A, we know two things:

1. The implementation will issue a diagnostic for any
program that contains a constraint violation, and

2. Any program that is accepted without a diagnostic will
behave as specified by the relevant ISO standard.

About the implementation done by group B, we know essentially
nothing. Probably it will behave like ISO C in most cases, but
there's no way to be sure without a careful reading of the
documentation done for implementation B, and even then we might
not know. Furthermore, when the next release arrives things
might be different, because group B has decided on their own what
language to implement. Granted, group B's language(s) will be a
lot like standard C, but just how much is up to them - having
abandoned the principle of conformance in one area, we may
reasonably expect they may be lax about conformance in another
area.

Suppose Group B makes the following guarantees:

1. Our implementation fully conforms to the 2011 C standard as a
freestanding implementation *except* that floating-point and
types "long long" and "unsigned long long" are not supported,
and the widest integer types are 32 bits. (A few additional
paragraphs would be needed to cover the ramifications, such as
the types used for intmax_t and the behavior of
preprocessor expressions.)

2. Our implementation will issue a diagnostic for any program
that contains a constraint violation (and for any program that
violates the restrictions stated in (1)).

3. Any program that is accepted without a diagnostic will behave
as specified by the 2011 ISO C standard.


Obviously that would be a different hypothetical (let me call
it B'). A key difference is I think B' is much less likely to
occur than either A or B - once a group has decided to be "not
conforming", they won't care so much about paying attention to
conformance in other areas.
I think you're stretching the meaning of a "conforming
implementation", not necessarily beyond the Standard's definition
of that term, but beyond what is reasonable. I think that a
typical user would think of a compiler that rejects any use of
floating-point as non-conforming. The fact that it can be
justified by citing the standard would be at best an interesting
but obscure curiosity. (That's pretty much how I think of it,
and I'm far more pedantic than a typical user.)

With all due respect, I think you're reading something into the
Standard that it doesn't say and doesn't mean to say. Being a
conforming implementation clearly is not the same as being a
high-quality implementation. Apparently you think of being
conforming as guaranteeing some minimal level of quality (in
terms of what programs it will execute correctly). It doesn't,
nor was it meant to.
 
K

Keith Thompson

Tim Rentsch said:
This comment glosses over an important distinction, namely,
the difference between "accept" and "translate and execute".
Conforming implementations are required to "translate and
execute" only one program, but they are required to "accept"
any strictly conforming program.
[...]

I don't see how that's an important distinction.

What does it mean for an implementation to "accept" a program that it
fails to translate and execute? How would accepting but not tranlating
a program be useful?

[snip]
Furthermore this result coincides with an intuitive sense of what
"freestanding" means, namely, for minimal environments. How
minimal is minimal? Pointedly, the Standard doesn't say. So
even though carrying that reasoning down to very small sizes
might be unexpected, I don't think it is contrary to the spirit
of the notion that freestanding implementations may be "tiny", so
be prepared to accept them as such.

Certainly freestanding implementations can be "tiny".

[...]
Not a compelling argument. Clearly there are existing hardware
targets having memory limitations severe enough so that
implementing even a single floating-point operation exceeds the
capacity of program memory. But the same model processor with
more memory might have enough room for floating-point operation
subroutines.

A failure to implement floating-point *at all* is not, IMHO, reasonably
considered to be a capacity limit. It's just missing functionality.
The lack is qualitative, not quantitative.

[...]
Suppose we have two groups of implementors, A and B. Group A has
decided to do a conforming implementation. Group B has decided
to implement "C-", which is most of C but leaves out some things
that they feel would impact the implementation too much, such as
floating point and 'long long'. The implementation of group A is
conforming working under the assumption of the thesis posited
above. The implementation of group B might or might not be
conforming under the same conditions.

Given this state of affairs, what do we know? About the
implementation done by group A, we know two things:

1. The implementation will issue a diagnostic for any
program that contains a constraint violation, and

2. Any program that is accepted without a diagnostic will
behave as specified by the relevant ISO standard.

About the implementation done by group B, we know essentially
nothing. Probably it will behave like ISO C in most cases, but
there's no way to be sure without a careful reading of the
documentation done for implementation B, and even then we might
not know. Furthermore, when the next release arrives things
might be different, because group B has decided on their own what
language to implement. Granted, group B's language(s) will be a
lot like standard C, but just how much is up to them - having
abandoned the principle of conformance in one area, we may
reasonably expect they may be lax about conformance in another
area.

Suppose Group B makes the following guarantees:

1. Our implementation fully conforms to the 2011 C standard as a
freestanding implementation *except* that floating-point and
types "long long" and "unsigned long long" are not supported,
and the widest integer types are 32 bits. (A few additional
paragraphs would be needed to cover the ramifications, such as
the types used for intmax_t and the behavior of
preprocessor expressions.)

2. Our implementation will issue a diagnostic for any program
that contains a constraint violation (and for any program that
violates the restrictions stated in (1)).

3. Any program that is accepted without a diagnostic will behave
as specified by the 2011 ISO C standard.


Obviously that would be a different hypothetical (let me call
it B'). A key difference is I think B' is much less likely to
occur than either A or B - once a group has decided to be "not
conforming", they won't care so much about paying attention to
conformance in other areas.


What you call B' is *exactly* what I've been talking about all along,
though I may not have been sufficiently clear about that.

I think that B' would be a very reasonable and useful thing to
implement. Its hypothetical authors care about conformance, but
recognize that they aren't able to provide it.

As for likelihood, I find your Group A, which claims standard
conformance while not supporting floating-point, to be less likely.
With all due respect, I think you're reading something into the
Standard that it doesn't say and doesn't mean to say. Being a
conforming implementation clearly is not the same as being a
high-quality implementation. Apparently you think of being
conforming as guaranteeing some minimal level of quality (in
terms of what programs it will execute correctly). It doesn't,
nor was it meant to.

The standard requires floating-point. It does not say that it's
optional, either for hosted or for freestanding implementations.
I would consider an implementer who claims full standard conformance
while rejecting all floating-point on the basis of a capacity
limitation to be disingenuous. I would consider an implementation
that *nearly* conforms to the C standard while acknowledging that
the lack of floating-point makes it non-conforming to be potentially
quite useful.
 
J

James Kuyper

This comment glosses over an important distinction, namely,
the difference between "accept" and "translate and execute".
Conforming implementations are required to "translate and
execute" only one program, but they are required to "accept"
any strictly conforming program.
[...]

I don't see how that's an important distinction.

It's only important as an example of under-specification in the C
standard. If "accept" was intended to be equivalent to "translate and
execute", the same phrase should have been used in both locations. If it
was intended to be different, then the difference should have been
clearly specified. "Translate and execute" is reasonably specific; at
least, I think I know what it means. It's "accept" that needs a more
precise definition. If the intent were that an implementation could not
comply with that requirement by simply displaying "Program accepted",
then the word "accept" was a bad choice for expressing that requirement.
Ordinary English usage allows someone to be described as accepting a
gift and then discarding it unused, and even unopened.
 
G

glen herrmannsfeldt

It's only important as an example of under-specification in the C
standard. If "accept" was intended to be equivalent to "translate and
execute", the same phrase should have been used in both locations.

In the OS/360 days, IBM had programs called "syntax checkers".
They didn't generate any code, but would verify that a program
was valid syntax before compilation. Presumably on smaller, slower,
systems it made sense to do the check separately.

Similarly, lint used to be used to do a better check of C source
than many compilers. That would "accept" but not "translate"
or "execute".

On the other hand, some systems might have enough memory to translate
(compile) but not execute some legal programs.
If it was intended to be different, then the difference should have
been clearly specified. "Translate and execute" is reasonably specific;
at least, I think I know what it means.

(snip)

-- glen
 
I

Ian Collins

glen said:
In the OS/360 days, IBM had programs called "syntax checkers".
They didn't generate any code, but would verify that a program
was valid syntax before compilation. Presumably on smaller, slower,
systems it made sense to do the check separately.

Similarly, lint used to be used to do a better check of C source
than many compilers. That would "accept" but not "translate"
or "execute".

Some environments still use lint. If you have a large code base, it
makes sense to split the build and checking phases.
 
S

Stephen Sprunk

,,,
On the other hand, some systems might have enough memory to
translate (compile) but not execute some legal programs.

Also, cross-compilers: the implementation is capable of translating a
conforming program but utterly incapable of executing it.

S
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
This comment glosses over an important distinction, namely,
the difference between "accept" and "translate and execute".
Conforming implementations are required to "translate and
execute" only one program, but they are required to "accept"
any strictly conforming program.
[...]

I don't see how that's an important distinction.

Surely the importance is obvious. The phrase "translate and
execute" implies running the program successfully and correctly.
The term "accept" does not imply that, only some milder notion
that does not relate to program execution.
What does it mean for an implementation to "accept" a program
that it fails to translate and execute? How would accepting
but not tranlating a program be useful?

Presumably it means something like "recognize as a correct
program". Personally I think that is useful, for much the same
reason that getting diagnostics for constraint violations is
useful. However, whatever different people may think about the
value of such a result is irrelevant - all that matters is the
Standard distinguishes the different cases, and clearly means one
to necessarily include program execution, and the other not.
Furthermore this result coincides with an intuitive sense of what
"freestanding" means, namely, for minimal environments. How
minimal is minimal? Pointedly, the Standard doesn't say. So
even though carrying that reasoning down to very small sizes
might be unexpected, I don't think it is contrary to the spirit
of the notion that freestanding implementations may be "tiny", so
be prepared to accept them as such.

Certainly freestanding implementations can be "tiny".

[...]
Not a compelling argument. Clearly there are existing hardware
targets having memory limitations severe enough so that
implementing even a single floating-point operation exceeds the
capacity of program memory. But the same model processor with
more memory might have enough room for floating-point operation
subroutines.

A failure to implement floating-point *at all* is not, IMHO,
reasonably considered to be a capacity limit. It's just missing
functionality. The lack is qualitative, not quantitative.

If a program uses a subroutine library that occupies 384K of
memory, and the target environment has only 256K of memory in it
(and no swapping or VM), the program cannot be run because the
amount of memory needed exceeds the memory capacity of the
machine in question.

If a program uses a floating-point operation that is implemented
using a subroutine that occupies 384 bytes of memory, and the
target environment has only 256 bytes of memory in it (and no
swapping or VM), the program cannot be run because the amount
of memory needed exceeds the memory capacity of the machine
in question.

Both of these situations clearly fall under the circumstances of
the penultimate entry of 1 p2 - the program in each case is of a
size or complexity which when translated objectively exceeds the
capacity of the target hardware. By contrast, the idea that
failing to execute the second program constitutes a "qualitative,
not quantitative" difference is a subjective judgment, and
moreover not related to any provision in the Standard.

Suppose we have two groups of implementors, A and B. Group A has
decided to do a conforming implementation. Group B has decided
to implement "C-", which is most of C but leaves out some things
that they feel would impact the implementation too much, such as
floating point and 'long long'. The implementation of group A is
conforming working under the assumption of the thesis posited
above. The implementation of group B might or might not be
conforming under the same conditions.

Given this state of affairs, what do we know? About the
implementation done by group A, we know two things:

1. The implementation will issue a diagnostic for any
program that contains a constraint violation, and

2. Any program that is accepted without a diagnostic will
behave as specified by the relevant ISO standard.

About the implementation done by group B, we know essentially
nothing. Probably it will behave like ISO C in most cases, but
there's no way to be sure without a careful reading of the
documentation done for implementation B, and even then we might
not know. Furthermore, when the next release arrives things
might be different, because group B has decided on their own what
language to implement. Granted, group B's language(s) will be a
lot like standard C, but just how much is up to them - having
abandoned the principle of conformance in one area, we may
reasonably expect they may be lax about conformance in another
area.

Suppose Group B makes the following guarantees:

1. Our implementation fully conforms to the 2011 C standard as a
freestanding implementation *except* that floating-point and
types "long long" and "unsigned long long" are not supported,
and the widest integer types are 32 bits. (A few additional
paragraphs would be needed to cover the ramifications, such as
the types used for intmax_t and the behavior of
preprocessor expressions.)

2. Our implementation will issue a diagnostic for any program
that contains a constraint violation (and for any program that
violates the restrictions stated in (1)).

3. Any program that is accepted without a diagnostic will behave
as specified by the 2011 ISO C standard.


Obviously that would be a different hypothetical (let me call
it B'). A key difference is I think B' is much less likely to
occur than either A or B - once a group has decided to be "not
conforming", they won't care so much about paying attention to
conformance in other areas.


What you call B' is *exactly* what I've been talking about all
along, though I may not have been sufficiently clear about that.


I'm not sure about that, because of what you say in the next
paragraph.
I think that B' would be a very reasonable and useful thing to
implement. Its hypothetical authors care about conformance, but
recognize that they aren't able to provide it.

Perhaps you don't realize this, but that's a stronger condition
than what you gave previously. To wit, the revised description
ascribes to the authors a belief that their implemention must
be nonconforming. This is important because it is precisely
this question that we trying to answer. In short, the revised
description begs the question.
As for likelihood, I find your Group A, which claims standard
conformance while not supporting floating-point, to be less
likely.

You keep using the word "claim". This is a mischaracterization.
Group A is not making any claim about conformance. I have stated
as part of the hypothetical that their Group A's implementation
is conforming in the sense I've described (which I believe is
consistent with both the letter and the spirit of the Standard,
but that's my statement, not theirs). I deliberately avoided any
mention of what either gruop believes as to whether either
implementation is conforming.

The standard requires floating-point. It does not say that it's
optional, either for hosted or for freestanding implementations.
I would consider an implementer who claims full standard
conformance while rejecting all floating-point on the basis of a
capacity limitation to be disingenuous. I would consider an
implementation that *nearly* conforms to the C standard while
acknowledging that the lack of floating-point makes it
non-conforming to be potentially quite useful.

You're trying to change the subject. The motives and beliefs of
the implementors are irrelevant to the question of conformance.
If you want to think that implementors like those described as
Group A are rat bastards, you are certainly welcome to do so.
But it has no bearing on whether such an implementation is in
fact conforming, which is the only question relevant to the
original point of discussion.

Over the course of the discussion, I have reviewed passages in
both the Standard and the Rationale documents, to double check
myself and the statements I have offered. I found nothing
inconsistent. I understand that you find the idea of a "subset"
implementation being conforming to be distasteful. But can you
support the "it isn't conforming" position with citations from
those documents? Or is it just that this notion of conformance
is not consistent with your intuition about what "conformance"
is supposed to mean?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top