On 2024-06-23 16:02, 'Heinz-Bernd Eggenstein' via [PiDP-11] wrote:
> >Was that with some different code then? Because I compiled the test
> >program under 2.11BSD and I got the mixed pointer assignment warning
> >about line 7, but none of the other things.
>
> This was in reference to the discussion what happens when you call emit
> with more than one (integer) arguments. So it's the original code from
> the thread starter just with emit(0); replaced by emit(0,2,4,6);
> Note that this is the ANSI-C version of the code (1st message in the
> thread), not the K&R version from the second message in the thread...if
> we want to demonstrate the difference between the ANSI and K&R version
> of the compilers, I think it's the fair comparison. ANSI-C vs. K&R C.
Ah. Yeah, I would expect the compiler to barf in ANSI C if you throw the
wrong number of arguments on it. :-)
> > It's just you who have a problem with some bits that are irrelevant are
> > not set to a value that you think they should be.
>
> The fact that a double with the first 16 bits set to zero is a legal
> representation of the double 0.0 irrespective of the other bits is,
> IMHO, just a lucky coincidence here, it's not like the compiler is
> smart enough to optimize this there.
I agree that the compiler isn't smart enough to optimize this. Because
the compiler have no clue that the emit() function expects a floating
point. I would sortof disagree that it's a lucky coincidence that it
would out correctly for 0, though. I would suspect it was a conscious
choice by the designers of the hardware. There are times when this can
be used to do shortcuts in code.
> > But you seem to demontrate that emit actually would make use
> >of all arguments actually given. Now you got me curious, because C have
> >no way of telling how many arguments were actually given. So I wonder
> >how on earth that works... My expectation would have been that it would
> >only have processed the first argument and ignored all the rest.
>
> IMHO, the code implementing the function will just grab 8 bytes from the
> stack and treat them as a double, and the code that is calling emit in
> the K&R version will just push whatever you give it as an argument on
> the stack, no matter of type, but might use a special instruction for
> "0" or "0.0" values as optimization. But not because it knowns that it
> will not matter because of the special way zero is represented in PDP-11
> doubles: at that point the K&R compiler is not aware of what emit is
> expecting as an argument type, so it cannot optimize for it. It just
> pushes *any type*, and *any number* of arguments to the stack and then
> calls the function. No Checks, no type conversion. And yes, this is
> correct as K&R doesn't claim to do anything else, but we might argue
> whether this is what people (like the thread starter) expect to happen.
Ah. Very good point. Yes, I think that is very correct. The code just
grabs the top 8 bytes, which in the case of multiple arguments just
happens to would out that way.
Thing is, though. Because of how data is represented on the PDP-11, this
means that for a 0, it will work correctly both for integer and floating
point, without any additional tricks. Which is very convenient and nice.
The end result is that you, when you write code, expects to get a zero,
and you are getting that. So it does what you expect it to do. And it
accomplish it without having to do any type checks or type conversions
or anything.
I think it's wrong to expect bits that are not relevant should have some
specific value in them, though.
And yes, the calling side just push whatever arguments you give, without
any understanding what the called side will do with the arguments, or
how to interpret them. With K&R C, that is a mental contract of the
programmer to which the compiler do not provide any assistance.
But the PDP-11 architecture itself defines a floating 0.0 as identical
to a integer 0, looking at the same address for the data, and that have
nice implications.
But clearly the compiler have no actual clue what you are doing, which
is why, in the K&R compiler, you get bad results for all the other cases
where you give an integer.
Which means you do not get what you expect for non-zero values, unless
you make sure they are of the correct type yourself.
> And yes, I use "expect" here in a totally subjective way, as in "what I
> think will happen, intuitively", and not in a normative way "what I
> think should happen according to the book". Expectations can be right or
> wrong. Sorry that was a bit sloppy in my message.
For me, I expect it to be "correct" in the sense that the operations and
results are the ones I would expect. Non-relevant bits are not something
I have any expectation on. And C is usually very liberal about leaving
such bits and bytes with all kind of random content.
I might have been focusing too much on the 0 case here though. Clearly
for any other values, you are not getting what you might have expected.
Which is just because the compiler isn't smart at all. The designers of
the architecure "saved" you for the 0 case, and the mantissa bits are
clearly allowed to be anything. So all is good there. And I don't see
any reason to complain about anything around that bit.
But you are correct in that K&R C will give you bad results in most
cases if you give the wrong type of arguments to a function call, and
the compiler neither fix things, nor warn you.
> P.S.:
> I think one legitimate objection to the "semi-broken" thing tho might be
> the following: in K&R times, nobody would just trust the C compiler to
> produce "good" code or the code you wanted/expected, you would also run
> "lint" across your code.
>
> And sure enough, 2.11BSD lint from K&R times will complain that
> emit(0);
> and all the other calls of emit from the thread starter's example code
> except the one with pi is "arg. 1 used inconsistently".
>
> If you change that to
> emit(0.0,1.0);
> lint will warn you about "variable # of args"
lint was usually the tool to check for these kind of "bugs", yes.
> In the words of "K&R" : "Existing compilers provide no run-time checking
> of array-subscripts, argument types, etc. For those situations where
> strong type checking is desirable, a sepearate version of the compiler
> is used. This program is called lint, apparently because it picks bits
> of fluff from one's programs. lint does not generate code.[...]"
I wouldn't even call lint a compiler. :-)
> Maybe we can agree on this?
For sure.