Reading from files and range of char and friends

T

Tim Rentsch

Spiros Bousbouras said:
But 6.2.6.2 p3 uses the word "only" and does not list reading from a
file as a way to generate a negative zero.

That is a true statement. Despite that, it is still obvious that the
Standard allows getc() to return a negative zero, based on the
description of fgetc() and on the rule for how unsigned-to-signed
conversion works.
 
T

Tim Rentsch

Keith Thompson said:
Sure, it's easy to do that by adding an invocation of
AVOID_NEGATIVE_ZERO() to every expression where you want to avoid
a negative zero result -- something that is of no benefit unless
your code is actually running on a system that has negative zeros.

Yes, perhaps my comment was a little bit too glib. Still,
I can't help feeling that the Standard imposes unnecessarily
severe restrictions on implementations, especially since the
restrictions are relevant only in rare circumstances, and
don't absolutely have to be there at all since it would be
easy to deal with negative zeros even in their absence.

True. Think of it as advice for hardware designers. (Not that
there's any particular reason they should listen to me.)

I agree with the advice, just think it's unlikely to be
efficacious to address comments to hardware designers in
this newsgroup.
 
J

James Kuyper


Huh? It's precisely that message that left me, too, with the impression
that you were confusing those two things.
clearly demonstrates. But if it is indeed symmetric and transitive
then it follows that using a function argument of unsigned char where
the function prototype says char should be ok.

I don't see how you reach that conclusion. Could you explain in detail
how you apply symmetry and transitivity to reach that conclusion - and
you must do so without confusing "same representation and alignment"
with compatibility. I don't even see how you reach that conclusion by
assuming that they are the same thing, or at least that the "same
representation and alignment" implies "compatible"; I certainly don't
see how you could reach it without making such an incorrect assumption.
 
J

James Kuyper

No , I didn't miss the point. My post you are quoting addresses this
very point by explaining how someone other than myself can answer
questions about this alternative C. Here is a more detailed
explanation: the way they could do that is by taking the current
standard , making the modification I suggested and then they would have
a description of how this alternative C is supposed to work. By
consulting this description they can answer questions about the
language. In fact , at least 1 person in the thread did address my
question which means they cared somewhat about the answer.

When I combine that explanation with the definitions of fread() and
fwrite(), I do get answers, but I doubt that they're the ones you
intended (if you even gave thought to that issue). The simplest fix
would be to convert references to unsigned char into 'int' in those
definitions, as well. However, that would prohibit the reading or
writing of objects with a size that is not a multiple of sizeof(int).
There's an old saying "you can never change just one thing", and this is
prime example. You need to add considerable detail to your hypothetical
alternative C before it will be sufficiently well defined to permit
asking such questions.
 
S

Spiros Bousbouras

Huh? It's precisely that message that left me, too, with the impression
that you were confusing those two things.

Above I should have said "unsigned char*" and "char*". I hope it wasn't
this omission which caused the confusion. If you thought that I did
really mean "unsigned char" and "char" then ignore what follows and
apologies for my mistake.
I don't see how you reach that conclusion. Could you explain in detail
how you apply symmetry and transitivity to reach that conclusion - and
you must do so without confusing "same representation and alignment"
with compatibility.

From 6.2.5 p27

A pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.39)

And footnote 39 says

The same representation and alignment requirements are
meant to imply interchangeability as arguments to functions,
return values from functions, and members of unions.

In what follows SRAR(T1 , T2) will mean that type T1 has the same
representation and alignment requirements as type T2. The syllogism
goes as follows:
1) SRAR(void* , unsigned char*) from 6.2.5 p27
2) Using symmetry and 1) we get that SRAR(unsigned char* , void*)
3) SRAR(void* , char*) from 6.2.5 p27
4) Using 2) , 3) and transitivity we get that
SRAR(unsigned char* , char*)
5) Using footnote 39 and 4) we get that unsigned char* and char* are
interchangeable as arguments to functions. Therefore wherever you
can use unsigned char* as an argument to a function you can also
use a char* and vice versa regardless of the existence of function
prototypes or anything else.

I realise that footnotes are not normative but this particular footnote
is misleading which is what I'm complaining about. If footnote 39 were
extended to say "...provided no compatibility rules are violated" I
wouldn't be complaining.
 
S

Spiros Bousbouras

When I combine that explanation with the definitions of fread() and
fwrite(), I do get answers, but I doubt that they're the ones you
intended (if you even gave thought to that issue).

I don't think I did. But I have already said that my excursion into an
alternative C was misguided so there's no point spending any more time
on this.
 
J

James Kuyper

Above I should have said "unsigned char*" and "char*". I hope it wasn't
this omission which caused the confusion. If you thought that I did
really mean "unsigned char" and "char" then ignore what follows and
apologies for my mistake.

I did think you meant unsigned char and char; but since unsigned char*
and char* are also incompatible, I still disagree with your conclusion.
From 6.2.5 p27

A pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.39)

And footnote 39 says

The same representation and alignment requirements are
meant to imply interchangeability as arguments to functions,
return values from functions, and members of unions.

In what follows SRAR(T1 , T2) will mean that type T1 has the same
representation and alignment requirements as type T2. The syllogism
goes as follows:
1) SRAR(void* , unsigned char*) from 6.2.5 p27
2) Using symmetry and 1) we get that SRAR(unsigned char* , void*)
3) SRAR(void* , char*) from 6.2.5 p27
4) Using 2) , 3) and transitivity we get that
SRAR(unsigned char* , char*)
5) Using footnote 39 and 4) we get that unsigned char* and char* are
interchangeable as arguments to functions.

That's where you went wrong, which is pretty much as I had expected.
The footnote about interchangeability does not impose any actual
requirement that they be interchangeable. The only actual requirement is
SRAR(unsigned char*, char*). The footnote is a non-normative expression
of the belief that this requirement implies interchangeability. It is
perfectly feasible for types with the same representation and alignment
requirements to not be interchangeable, which means that belief is
incorrect. An implementation where they are not, in fact,
interchangeable, could be fully conforming.
I realise that footnotes are not normative but this particular footnote
is misleading which is what I'm complaining about. ...

I do agree that it's misleading, and should be changed. My preference
would be to drop the weasel-wording about "is intended to", and change
it into normative text mandating interchangeability, overriding any
contrary conclusions that might otherwise be reached by applying the
compatibility rules.
 
S

Spiros Bousbouras

I did think you meant unsigned char and char; but since unsigned char*
and char* are also incompatible, I still disagree with your conclusion.


That's where you went wrong, which is pretty much as I had expected.
The footnote about interchangeability does not impose any actual
requirement that they be interchangeable. The only actual requirement is
SRAR(unsigned char*, char*). The footnote is a non-normative expression
of the belief that this requirement implies interchangeability.

Ok but I can't imagine how you concluded from that that I confused SRAR
with compatibility.
It is
perfectly feasible for types with the same representation and alignment
requirements to not be interchangeable, which means that belief is
incorrect.

Couldn't we instead resolve the contradiction by saying that the belief
is correct but SRAR is not transitive ? What would break with such an
approach ? I'm thinking that the function

int foo(void) {
char c = 0 , *p = &c ;
unsigned char *up = (unsigned char *)p ;
signed char *sp = (signed char *)up ;

return p == (char *)up && p == (char *)sp &&
up == (unsigned char *)sp &&
sp == (signed char *)p ;
}

would no longer be guaranteed to return 1 and that's a problem.
An implementation where they are not, in fact,
interchangeable, could be fully conforming.


I do agree that it's misleading, and should be changed. My preference
would be to drop the weasel-wording about "is intended to", and change
it into normative text mandating interchangeability, overriding any
contrary conclusions that might otherwise be reached by applying the
compatibility rules.

I'm not sure I follow. Are you saying that the standard should mandate
that unsigned char* and char* should be interchangeable ? (Or at least
that would be a consequence of what you're suggesting.)
 
J

James Kuyper

Ok but I can't imagine how you concluded from that that I confused SRAR
with compatibility.

I didn't know which mistake you made; I couldn't put together any valid
argument for your conclusion; I made a guess as to which mistake you
might have made to reach that conclusion.
Couldn't we instead resolve the contradiction by saying that the belief
is correct but SRAR is not transitive ?

There are three problems with that approach:
a) it's relatively straightforward to demonstrate that the belief is
incorrect (for example, the two types could be passed as inputs or
return values from a function using different registers), so assuming
that it's correct would be an error.
b) SRAR can trivially be proved to be transitive, simply by the
definition of the word "same", so assuming that it's not transitive
would be a second error.
c) There is no contradiction, once you understand the issues correctly.
Therefore, using the supposed existence of a contradiction to justify
believing two false things would be a third error.
... What would break with such an
approach ?

Everything. If you start with two contradictory premises (for example,
that "same" has it's ordinary English meaning, and that SRAR is not
transitive), it's possible, through perfectly valid logical operations,
to prove as a conclusion that ANY statement you wish is true - or false
- your choice. That would render the entire C standard pointless.
I'm thinking that the function

int foo(void) {
char c = 0 , *p =&c ;
unsigned char *up = (unsigned char *)p ;
signed char *sp = (signed char *)up ;

return p == (char *)up&& p == (char *)sp&&
up == (unsigned char *)sp&&
sp == (signed char *)p ;
}

would no longer be guaranteed to return 1 and that's a problem.

It would be guaranteed to return 1. It would also be guaranteed to not
return 1. It could also be proven that the result is
implementation-defined. Or, that it's not implementation-defined. I hope
you can see why this would be a bit of a problem.
I'm not sure I follow. Are you saying that the standard should mandate
that unsigned char* and char* should be interchangeable ? (Or at least
that would be a consequence of what you're suggesting.)

That's one possible approach: the standard could be modified to state
that interchangeable types are guaranteed compatible with each other.
Another approach would be to modify every constraint that currently
requires compatibility to allow either compatibility or interchangeability.
 
S

Spiros Bousbouras

[...]
Couldn't we instead resolve the contradiction by saying that the belief
is correct but SRAR is not transitive ?

There are three problems with that approach:
a) it's relatively straightforward to demonstrate that the belief is
incorrect (for example, the two types could be passed as inputs or
return values from a function using different registers), so assuming
that it's correct would be an error.

I don't see what that has to do with anything. Even types which are
compatible and therefore interchangeable can be passed using different
registers.
b) SRAR can trivially be proved to be transitive, simply by the
definition of the word "same", so assuming that it's not transitive
would be a second error.

The standard doesn't define "same" and it wouldn't be the first time
the standard uses a word with a different meaning than the established
one. For example "byte" usually means a quantity of 8 bits but that's
not how the standard defines it. It also uses "overflow" in a
specialised manner , the computing common sense meaning of the word is
simply that a quantity exceeds some bounds.
c) There is no contradiction, once you understand the issues correctly.
Therefore, using the supposed existence of a contradiction to justify
believing two false things would be a third error.

If the belief is incorrect then there is a contradiction between the
belief and reality.
Everything. If you start with two contradictory premises (for example,
that "same" has it's ordinary English meaning, and that SRAR is not
transitive), it's possible, through perfectly valid logical operations,
to prove as a conclusion that ANY statement you wish is true - or false
- your choice. That would render the entire C standard pointless.

If one assumes that "same" has its ordinary English meaning and if one
used formal logic to derive consequences from the standard (which would
be rather hard to do since the standard is not written in a formal
language) and if one chose a logic which contains the rule that from a
contradiction you can derive anything then one could indeed conclude
that any statement is both true and false. But since people use
informal reasoning to draw conclusions from the standard I don't think
that your excursion into logic is relevant to the discussion.

I note also that if the standard is found to have a contradiction it
will not be rendered pointless just less useful. Even mathematics for
parts of its history had contradictions and people knew it but it
didn't make it pointless.

So the question is , does the assumption that SRAR is transitive
provide guarantees useful for C programming which one wouldn't have
without this assumption ? I attempted an example with foo() below where
I think it is useful to know that it will always return 1.
It would be guaranteed to return 1. It would also be guaranteed to not
return 1. It could also be proven that the result is
implementation-defined. Or, that it's not implementation-defined. I hope
you can see why this would be a bit of a problem.

It would be a problem but it doesn't follow.
That's one possible approach: the standard could be modified to state
that interchangeable types are guaranteed compatible with each other.
Another approach would be to modify every constraint that currently
requires compatibility to allow either compatibility or interchangeability.

But with such a modification a compiler would not have to warn you if
you did for example strcmp(p1 , p2) and p1 has type unsigned char* .
Don't you think this might create problems ? Personally I don't have a
problem with the constraints in this area but I would want at the end
of footnote 39 the addition "provided no compatibility rules are
violated".
 
K

Keith Thompson

Spiros Bousbouras said:
On Sun, 20 Mar 2011 18:44:04 -0400


The standard doesn't define "same" and it wouldn't be the first time
the standard uses a word with a different meaning than the established
one. For example "byte" usually means a quantity of 8 bits but that's
not how the standard defines it. It also uses "overflow" in a
specialised manner , the computing common sense meaning of the word is
simply that a quantity exceeds some bounds.

The standard provides its own definitions for "byte" and "overflow".
If it *doesn't* provide a definition for a word, especially a
common English word with no special technical usage, that implies
that it's used in the common English sense.

[...]
 
J

James Kuyper

I don't see what that has to do with anything. Even types which are
compatible and therefore interchangeable can be passed using different
registers.

It seemed perfectly obvious to me what interchangeability means, but if
you can actually believe that the above sentence makes any sense
whatsoever, we must differ in our understanding of that term at a very
fundamental level. To figure out where our understandings differ, I'm
going to have to explain my own understanding in tedious detail; feel
free to explain your own understanding of the term in similar detail, or
simply identify the differences.

There are seven cases where the standard currently requires "same
representation and alignment" (and incorrectly suggests in non-normative
footnotes that this implies interchangeability as arguments to
functions, return values from functions, and members of unions):

6.2.5p13: "D _Complex" and "D[2]", where D can be float, double, or long
double.

6.2.5p26: "T" and cv T", where T can be any type mentioned before
earlier in that same section, and cv is "const", "volatile", or both.

6.2.5p27:

void*, char*, unsigned char*, signed char*.

"cv1 T1*" and "cv2 T2*", where T1 and T2 are compatible types, and cv1
and cv2 can each be const, volatile, const volatile, or absent.

"struct tag1*" and "struct tag2*"

"union tag3*" and "union tag4*"

G4: "D _Imaginary" and "D"

A type obviously has the same representation and alignment with itself;
less obviously, but explicitly stated in the standard, a type is always
compatible with itself. For most of the cases above where the two types
are different, the types are not compatible. The one exception I could
identify: if cv1==cv2, but T1!=T2, cv1 T1 and cv2 T2 are different but
compatible types. Furthermore, most of those cases do not allow for
implicit conversion - the exception being those involving qualifiers.

Whenever a pair of SRAR types is not compatible and have no implicit
conversions between them, using one in place of the other is generally
at least a constraint violation, and otherwise has undefined behavior (I
didn't notice any cases where it has implementation-defined behavior,
but I may have missed a case).

If it's a constraint violation, the implementation is required to
diagnose the program, and is not required to translate or execute it.
Therefore, it seems to me that interchangeability, if it were indeed
implied by SRAR, would be meaningful only in those cases which have
undefined behavior. It can only mean that, despite the fact that the
behavior is undefined by the standard, the forms of behavior that are
actually possible are constrained by the fact that they are SRAR types,
to produce the expected results.

By "expected results", I mean the following: for pointers, the pointer
value received will point at the same location in memory, though with a
different type. For _Complex, the corresponding array of double will
contain the real and imaginary components of the complex number. For
_Imaginary, the corresponding real value will be the same as the
imaginary component of the the _Imaginary one. For the cases which
differ in cv-qualification, the values will be the same as if by
implicit conversion.

For interchangeability as function arguments:
6.5.2.2p6:
a) A function is called with a K&R style declaration in scope. The
promoted type of an argument passed to the function is not compatible
with the type of the corresponding parameter in the function's
definition, but they are SRAR types.
b) A function is called with a prototype that ends with an ellipsis,
follows those same rules with respect to parameters after the last
declared parameter.
Note that this clause contains an exception that says, in effect, that
void* and pointers to character types are interchangeable - but only in
these contexts.

6.5.2.2p9: A function is called with a prototype in scope that specifies
a type for a parameter that is incompatible with the type declared for
that parameter in the function definition, but they are SRAR types.

In each of these cases, if the ABI used by the implementation calls for
the two SRAR types to be placed in different registers, then the calling
function will place the argument's value in one register, but the
calling function will try to retrieve it from a different register. Such
an ABI would impose severe complications on <stdarg.h> if it applied to
functions with a variable number of arguments, but for calls to other
types of functions it's not particularly odd or hard to implement (it
would be hard to motivate such an ABI feature, but that's not relevant
to my argument).
With such an ABI, the attempt to interchange the types has failed,
because the information was not successfully passed from the calling
function to the called function.

For interchangeability as return types from functions:
6.5.2.2p9: a function is called with a prototype in scope that specifies
a return type that is incompatible with the return type specified in the
function definition, but they are SRAR types.

In this case, if the ABI used by the implementation specifies that the
two SRAR types must be placed in different registers, then the called
function will place it's return value in one register, while the calling
function will attempt to read that value from a different register.
Attempting to interchange the types has failed again, because the
information was not successfully passed from the called function to the
calling function.

For interchangeability of SRAR types as members of unions, I cannot come
up with a good counter-example. This might be because the standard is
right in this case, but it's more likely due to a lack of imagination on
my part.
The standard doesn't define "same" and it wouldn't be the first time
the standard uses a word with a different meaning than the established
one. ...

The rule is that if an alternative definition, provided neither by the
standard itself, nor by ISO/IEC 2382−1 or ISO 31−11, the the meaning
from ordinary English (as used in IT contexts) applies. I don't have
copies of either ISO/IEC 2382−1 or ISO 31−11, so I can't be sure, but I
doubt that either one of them provides a definition of the word "same"
that is sufficiently unconventional as to invalidate SRAR transitivity.
... For example "byte" usually means a quantity of 8 bits but that's
not how the standard defines it. It also uses "overflow" in a
specialised manner ,

In both cases, the standard explicitly provides the alternative
definition that applies when those terms are used in the context of the
standard. The standard provides no alternative definition for "same",
and gives us no reason to suspect that any meaning other than the
conventional English meaning is intended.
If the belief is incorrect then there is a contradiction between the
belief and reality.

Yes, but that's not the contradiction you were describing. You were
describing a non-existent contradiction between SRAR(unsigned char*,
char*) and the fact that they are incompatible types. That incorrect
belief was an essential step in reaching the faulty conclusion that
there was a contradiction between those two facts.

....
If one assumes that "same" has its ordinary English meaning and if one
used formal logic to derive consequences from the standard (which would
be rather hard to do since the standard is not written in a formal
language) and ....
... if one chose a logic which contains the rule that from a
contradiction you can derive anything ...

That's not a special rule for a special kind of logic. It's a fact
derivable from the ordinary rules of conventional logic.
... then one could indeed conclude
that any statement is both true and false. But since people use
informal reasoning to draw conclusions from the standard I don't think
that your excursion into logic is relevant to the discussion.

Reaching a conclusion of "not-A" from an argument whose premises include
"A", is a little too informal for my tastes. Your tastes may differ, in
which case we have nothing useful to discuss.
So the question is , does the assumption that SRAR is transitive
provide guarantees useful for C programming which one wouldn't have
without this assumption ?

I think the derived fact (NOT an assumption) that SRAR is transitive is
precisely as useful as SRAR itself. In a theoretical sense, both are
pretty much useless, without the corresponding guarantee of
interchangeability. In a practical sense, interchangeability of SRAR
types is a reality on most real systems, making SRAR moderately useful,
and the transitivity of SRAR comparably useful.

....
But with such a modification a compiler would not have to warn you if
you did for example strcmp(p1 , p2) and p1 has type unsigned char* .
Don't you think this might create problems ?

No, not really. I would expect that anyone writing such code would
intend to produce precisely the behavior that would be produced by
reason of the newly-guaranteed interchangeability of char* and unsigned
char*. If so, the author would be annoyed, rather than pleased, to
receive such warnings.
... Personally I don't have a
problem with the constraints in this area but I would want at the end
of footnote 39 the addition "provided no compatibility rules are
violated".

Keep in mind that footnotes are non-normative, so placing such a clause
in a footnote would be pointless. Footnotes are supposed to point out
in-obvious facts that can be derived from the facts given in normative
text; footnotes cannot be the source of new facts about C.
Interchangeability was supposedly derivable from "same representation
and alignment"; my objection is not to the interchangeability, but to
the fact that is not in fact derivable from those things.
 
L

lawrence.jones

James Kuyper said:
There are seven cases where the standard currently requires "same
representation and alignment" (and incorrectly suggests in non-normative
footnotes that this implies interchangeability as arguments to
functions, return values from functions, and members of unions):

The footnotes don't imply that interchangeability is required, they say
that it is intended to work. This is guidance to implementors: If you
can possibly make it work, you should. If you can't, you still conform,
but users are going to be disappointed.
Keep in mind that footnotes are non-normative, so placing such a clause
in a footnote would be pointless.

People frequently misunderstand what "non-normative" means. All it
means is that the text cannot contain requirements ("shall" or "shall
not" statements), not that it has no force.
 
S

Spiros Bousbouras

The standard provides its own definitions for "byte" and "overflow".

Strictly speaking the standard doesn't define "overflow" , section 3
only mentions the word in an example. The closest thing I can find to a
definition is the following quote from 6.2.5 p9

A computation involving unsigned operands can never
overflow, because a result that cannot be represented by
the resulting unsigned integer type is reduced modulo the
number that is one greater than the largest value that can
be represented by the resulting type.

This isn't so much a definition as an indication that the standard is
going to be using "overflow" in an unusual manner.
If it *doesn't* provide a definition for a word, especially a
common English word with no special technical usage, that implies
that it's used in the common English sense.

That is also my default assumption but on this occasion we are
confronted with the following 2 choices :

A. "Same" in footnote 39 is used with its common English meaning
therefore SRAR ([1]) is transitive therefore footnote 39 makes a false
claim.

B. "Same" in footnote 39 is used in an idiosyncratic manner (just like
"overflow") in which case SRAR is not necessarily transitive in which
case it is possible that footnote 39 does not make any false claims i.e.
types which satisfy SRAR() are indeed interchangeable.

Regardless of whether we choose A or B the standard has a flaw.
(I consider a false claim a flaw even if it appears in non normative
text.) So the question is , which of A and B is the less severe flaw ?

Now , James Kuyper is arguing , assuming that I'm not misunderstanding
him , that even if we choose B , footnote 39 still makes a false claim.
If he is correct then clearly we should adopt A because adopting B
doesn't buy us anything. But if he's not correct then we should make the
choice on a different basis.

As I have said already I would prefer it if SRAR() were symmetric and
transitive so that

int foo(void) {
char c = 0 , *p = &c ;
unsigned char *up = (unsigned char *)p ;
signed char *sp = (signed char *)up ;

return p == (char *)up && p == (char *)sp &&
up == (unsigned char *)sp &&
sp == (signed char *)p ;
}

is guaranteed to always return 1 but my preferences are not a basis on
which to interpret the standard.

[1] <[email protected]>
http://groups.google.com/group/comp.lang.c/msg/3f8849e777e60db9?dmode=source
 
K

Keith Thompson

Spiros Bousbouras said:
The standard provides its own definitions for "byte" and "overflow".

Strictly speaking the standard doesn't define "overflow" , section 3
only mentions the word in an example. The closest thing I can find to a
definition is the following quote from 6.2.5 p9

A computation involving unsigned operands can never
overflow, because a result that cannot be represented by
the resulting unsigned integer type is reduced modulo the
number that is one greater than the largest value that can
be represented by the resulting type.

This isn't so much a definition as an indication that the standard is
going to be using "overflow" in an unusual manner.
If it *doesn't* provide a definition for a word, especially a
common English word with no special technical usage, that implies
that it's used in the common English sense.

That is also my default assumption but on this occasion we are
confronted with the following 2 choices :

A. "Same" in footnote 39 is used with its common English meaning
therefore SRAR ([1]) is transitive therefore footnote 39 makes a false
claim.

It's best to refer to footnotes by the section and paragraph to which
they apply. Footnote 39 happens to be the same in the original C
standard and N1256, but later foonotes differ. It applies to 6.2.5p26.

I think your option A is the general consensus; the footnote
claims to state something that's implied by the normative text,
but a careful reading of the normative text indicates that it isn't.
B. "Same" in footnote 39 is used in an idiosyncratic manner (just like
"overflow") in which case SRAR is not necessarily transitive in which
case it is possible that footnote 39 does not make any false claims i.e.
types which satisfy SRAR() are indeed interchangeable.

This would require some *specific* meaning for the word "same".
It's implausible that the authors of the standard would use the
word "same" with a meaning that clearly differs from the usual one
without bothering to mention that they're doing so.

Even if this were the case, I can't think of a plausible meaning for
"same" that would make the footnote correct. (I admit I haven't
wasted^H^H^H^H^H^H spent much time trying to do so.)

You might as well speculate that they're using the word "The"
in some idiosyncratic manner.
Regardless of whether we choose A or B the standard has a flaw.
(I consider a false claim a flaw even if it appears in non normative
text.) So the question is , which of A and B is the less severe flaw ?

Now , James Kuyper is arguing , assuming that I'm not misunderstanding
him , that even if we choose B , footnote 39 still makes a false claim.
If he is correct then clearly we should adopt A because adopting B
doesn't buy us anything. But if he's not correct then we should make the
choice on a different basis.

Would you care to provide a plausible meaning for the word "same"
that makes the footnote correct? Can you confirm that this meaning
doesn't adversely affect the other uses of the word "same" in the
standard? (I didn't count them all, but the 100th occurrence is
in 6.5.8p5.)
As I have said already I would prefer it if SRAR() were symmetric and
transitive so that [snip]

int foo(void) {
char c = 0 , *p = &c ;
unsigned char *up = (unsigned char *)p ;
signed char *sp = (signed char *)up ;

return p == (char *)up && p == (char *)sp &&
up == (unsigned char *)sp &&
sp == (signed char *)p ;
}

is guaranteed to always return 1 but my preferences are not a basis on
which to interpret the standard.

All that requires is that round-trip conversions among char*,
unsigned char*, and signed char* preserve the original value; that
could be true even if all three had distinct representations and
alignment requirements.
 
K

Keith Thompson

The footnotes don't imply that interchangeability is required, they say
that it is intended to work. This is guidance to implementors: If you
can possibly make it work, you should. If you can't, you still conform,
but users are going to be disappointed.

I suggest that the wording of the footnote does not effective convey
that intent. In particular, I've always read the phrase "meant to
imply" to refer to a logical implication, not a recommendation.

Several sections of the standard have "Recommended practice"
subsections; the term is even defined in 3.16:

recommended practice

specification that is strongly recommended as being in keeping
with the intent of the standard, but that may be impractical
for some implementations

There are two footnotes that use the phrase "meant to imply", both in
section 6.2.5. I suggest that replacing both with a "Recommend
practice" subsection would be a substantial improvement.
People frequently misunderstand what "non-normative" means. All it
means is that the text cannot contain requirements ("shall" or "shall
not" statements), not that it has no force.

Can you expand on that a bit? What "force" can a footnote have
without imposing a requirement?

Oh, and speaking of footnotes, it would have been useful for N1256
to retain the same numbering of foonotes seen in the original C99
standard. Newly added foonotes might be labeled "42a", "42b", and
so forth. I think some Ada standard drafts have taken this approach.
(Section and paragraph numbers have *mostly* remained the same,
but those have also changed in a few cases.)
 
S

Spiros Bousbouras

Spiros Bousbouras said:
]
b) SRAR can trivially be proved to be transitive, simply by the
definition of the word "same", so assuming that it's not transitive
would be a second error.

The standard doesn't define "same" and it wouldn't be the first time
the standard uses a word with a different meaning than the established
one. For example "byte" usually means a quantity of 8 bits but that's
not how the standard defines it. It also uses "overflow" in a
specialised manner , the computing common sense meaning of the word is
simply that a quantity exceeds some bounds.

The standard provides its own definitions for "byte" and "overflow".

Strictly speaking the standard doesn't define "overflow" , section 3
only mentions the word in an example. The closest thing I can find to a
definition is the following quote from 6.2.5 p9

A computation involving unsigned operands can never
overflow, because a result that cannot be represented by
the resulting unsigned integer type is reduced modulo the
number that is one greater than the largest value that can
be represented by the resulting type.

This isn't so much a definition as an indication that the standard is
going to be using "overflow" in an unusual manner.
If it *doesn't* provide a definition for a word, especially a
common English word with no special technical usage, that implies
that it's used in the common English sense.

That is also my default assumption but on this occasion we are
confronted with the following 2 choices :

A. "Same" in footnote 39 is used with its common English meaning
therefore SRAR ([1]) is transitive therefore footnote 39 makes a false
claim.

It's best to refer to footnotes by the section and paragraph to which
they apply. Footnote 39 happens to be the same in the original C
standard and N1256, but later foonotes differ. It applies to 6.2.5p26.

The post appearing in [1] has full references. More relevant to the
discussion is the fact that footnote 39 is referenced in 6.2.5 p27.
I think your option A is the general consensus; the footnote
claims to state something that's implied by the normative text,
but a careful reading of the normative text indicates that it isn't.

When you say "general" how general do you mean ? Even outside the
present discussion ? And on what basis has this consensus been formed ?
This would require some *specific* meaning for the word "same".
It's implausible that the authors of the standard would use the
word "same" with a meaning that clearly differs from the usual one
without bothering to mention that they're doing so.

Perhaps they didn't realise at the time they were doing it. Perhaps
they didn't think through the consequences of using "same".
Even if this were the case, I can't think of a plausible meaning for
"same" that would make the footnote correct. (I admit I haven't
wasted^H^H^H^H^H^H spent much time trying to do so.)

Usual meaning minus the implication of transitivity.
You might as well speculate that they're using the word "The"
in some idiosyncratic manner.

I have no reason to do that. I did say above that my default assumption
is that common English words are used with their common meaning. But in
the case of "same" as it appears in footnote 39 this assumption leads
to problems.
Would you care to provide a plausible meaning for the word "same"
that makes the footnote correct? Can you confirm that this meaning
doesn't adversely affect the other uses of the word "same" in the
standard? (I didn't count them all, but the 100th occurrence is
in 6.5.8p5.)

I cannot confirm it but I find it unlikely that reducing the power of
"same" i.e. removing the implication of transitivity would have adverse
effects. More importantly , I wasn't suggesting that the possible
idiosyncratic usage of "same" in footnote 39 is also being used
elsehwere in the standard.
As I have said already I would prefer it if SRAR() were symmetric and
transitive so that
[snip]

You haven't snipped any text at this point !
All that requires is that round-trip conversions among char*,
unsigned char*, and signed char* preserve the original value; that
could be true even if all three had distinct representations and
alignment requirements.

Of course it could. But the relevant question is would it be guaranteed
to be true without assuming that SRAR() is symmetric and transitive ?
 
K

Keith Thompson

Spiros Bousbouras said:
On Tue, 22 Mar 2011 15:19:27 -0700
It's best to refer to footnotes by the section and paragraph to which
they apply. Footnote 39 happens to be the same in the original C
standard and N1256, but later foonotes differ. It applies to 6.2.5p26.

The post appearing in [1] has full references. More relevant to the
discussion is the fact that footnote 39 is referenced in 6.2.5 p27.

Yes, it's referenced in both paragraphs 26 and 27 (I hadn't
noticed that before). And footnote 31 has the same wording, and is
referenced in paragraph 9 (there it refers to corresponding signed
and unsigned integer types).
When you say "general" how general do you mean ? Even outside the
present discussion ? And on what basis has this consensus been formed ?

I've never seen any suggestion, other than yours, that "same"
is used in some intransitive sense here. Even after reading what
you've written about it, the idea doesn't make any sense to me.
If that were the intent, it would only make sense to use a word
other than "same".

[...]
Usual meaning minus the implication of transitivity.

The usual meaning of "same" is transitive. In common English usage, it
just doesn't make any sense to say that A is the same as B, and B is the
same as C, but A is not the same as C. Similarity can certainly be
non-transitive; sameness cannot.

If you were to suggest a mathematical relation that's like equality
"minus the implication of transitivity", I would be equally at a
loss to understand what you have in mind.
I have no reason to do that. I did say above that my default assumption
is that common English words are used with their common meaning. But in
the case of "same" as it appears in footnote 39 this assumption leads
to problems.

The footnote has problems. They're not caused by the use of the word
"same".

In fact, based on Larry Jones's recent post in thread, it appears that
neither of our understandings of that footnote match the intent.
Apparently it was intended to be implementation advice.
 
J

James Kuyper

On 03/22/2011 05:03 PM, Spiros Bousbouras wrote:
....
That is also my default assumption but on this occasion we are
confronted with the following 2 choices :

A. "Same" in footnote 39 is used with its common English meaning
therefore SRAR ([1]) is transitive therefore footnote 39 makes a false
claim.

B. "Same" in footnote 39 is used in an idiosyncratic manner (just like
"overflow") in which case SRAR is not necessarily transitive in which
case it is possible that footnote 39 does not make any false claims i.e.
types which satisfy SRAR() are indeed interchangeable.

The key problem here is that we have almost no clues about how this
idiosyncratic meaning of "same" differs from the ordinary one.
Regardless of whether we choose A or B the standard has a flaw.
(I consider a false claim a flaw even if it appears in non normative
text.) So the question is , which of A and B is the less severe flaw ?

Now , James Kuyper is arguing , assuming that I'm not misunderstanding
him , that even if we choose B , footnote 39 still makes a false claim.

Correct.
 

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,766
Messages
2,569,569
Members
45,045
Latest member
DRCM

Latest Threads

Top