Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

++ and —

167 views
Skip to first unread message

gdo...@gmail.com

unread,
Jun 26, 2022, 4:20:03 AM6/26/22
to
Interesting ++ and— can be used on floating point values.

Is this relatively new? Does C allow that?

Wuns Haerst

unread,
Jun 26, 2022, 8:25:12 AM6/26/22
to
Am 26.06.2022 um 10:19 schrieb gdo...@gmail.com:
> Interesting ++ and— can be used on floating point values.
>
> Is this relatively new? Does C allow that?

That's since C++17.

Alf P. Steinbach

unread,
Jun 26, 2022, 8:57:00 AM6/26/22
to
On 26 Jun 2022 10:19, gdo...@gmail.com wrote:
> Interesting ++ and— can be used on floating point values.
>
> Is this relatively new?

From the very start of standard C++.

C++98 §5.3.2/1 ❝The operand of prefix ++ is modified by adding 1, or set
to true if it is `bool` (this use is deprecated). The operand shall be a
modifiable lvalue. The type of the operand shall be an arithmetic type
or a pointer to a completely-defined object type. The value is the new
value of the operand; it is an lvalue. If `x` is not of type `bool`, the
expression `++x` is equivalent to `x+=1`.❞

C++98 §3.9.1/8 ❝Integral and floating types are collectively called
/arithmetic types/.❞


> Does C allow that?

C99 §6.5.3.1 (via N1256) ❝The operand of the prefix increment or
decrement operator shall have qualified or unqualified real or pointer
type and shall be a modifiable lvalue.❞

C99 §6.2.5/17: ❝The integer and real floating types are collectively
called /real types/.❞

C99 §6.2.5/10: ❝There are three /real floating types/, designated as
`float`, `double`, and `long double`❞

I don't know about C89.


- Alf

jak

unread,
Jun 26, 2022, 12:42:33 PM6/26/22
to
the Lattice C compiler 2.12 already worked in this way (it became
Microsoft C 2.0 in 1982)

>
>
> - Alf

Keith Thompson

unread,
Jun 26, 2022, 6:45:29 PM6/26/22
to
"gdo...@gmail.com" <gdo...@gmail.com> writes:
> Interesting ++ and— can be used on floating point values.

It looks like you typed "--" and your editor translated it to an EM-DASH "—".

> Is this relatively new? Does C allow that?

No, it's not new, and yes, C allows it.

A 1975 C reference manual says that ++ and -- cannot be applied to
floating-point types. Every later C or C++ reference, including K&R1
(1978), the 1990 ISO C standard and the first edition of Stroustrup's
"The C Programming Language" (1986) does not have this restriction.

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

Malcolm McLean

unread,
Jun 27, 2022, 8:40:52 AM6/27/22
to
On Sunday, 26 June 2022 at 09:20:03 UTC+1, gdo...@gmail.com wrote:
> Interesting ++ and— can be used on floating point values.
>
> Is this relatively new? Does C allow that?
>
It does. It shouldn't. Incrementing isn't the same as adding one, though
it's mathematically the same.
Incrementing means "go to the next / previous value in the set".
Adding one means "increase by a constant value which accidentally
happens to be unity".
For instance in football you get one point for a draw, three points for
a win. This should be coded as "if (scoresequal) points += 1;"
On the other hand if you are stepping through the table from top
team to bottom team, you should use "++" or "--" to manipulate
the index variable.
A floating point value is almost always in the first category.

Keith Thompson

unread,
Jun 27, 2022, 1:34:45 PM6/27/22
to
In C and C++, incrementing means adding one.

Ben Bacarisse

unread,
Jun 27, 2022, 3:49:33 PM6/27/22
to
Malcolm McLean <malcolm.ar...@gmail.com> writes:

> On Sunday, 26 June 2022 at 09:20:03 UTC+1, gdo...@gmail.com wrote:
>> Interesting ++ and— can be used on floating point values.
>>
>> Is this relatively new? Does C allow that?
>>
> It does. It shouldn't. Incrementing isn't the same as adding one, though
> it's mathematically the same.

In mathematics an increment is simply a (usually small) change. It need
not be by one, and it can even be negative.

> Incrementing means "go to the next / previous value in the set".

In what context? I don't think it has that meaning in plain English
(though many dictionaries, being sticklers, don't even acknowledge the
verb), and I don't think it does in mathematics either. And in C and
C++, incrementing means adding one.

> Adding one means "increase by a constant value which accidentally
> happens to be unity".

Or "increment by one" in most contexts but then I admit I don't know
what you mean by the one being an accident.

> For instance in football you get one point for a draw, three points for
> a win. This should be coded as "if (scoresequal) points += 1;"
> On the other hand if you are stepping through the table from top
> team to bottom team, you should use "++" or "--" to manipulate
> the index variable.
> A floating point value is almost always in the first category.

I agree with some of these conclusions. I often choose <obj> += 1 over
either ++<obj> or <obj>++ based on what the intended meaning is because
I prefer to think of ++ and -- as "next" and "previous", and += as
"increment by".

--
Ben.

Malcolm McLean

unread,
Jun 27, 2022, 5:32:52 PM6/27/22
to
On Monday, 27 June 2022 at 20:49:33 UTC+1, Ben Bacarisse wrote:
> Malcolm McLean <malcolm.ar...@gmail.com> writes:
>
> > On Sunday, 26 June 2022 at 09:20:03 UTC+1, gdo...@gmail.com wrote:
> >> Interesting ++ and— can be used on floating point values.
> >>
> >> Is this relatively new? Does C allow that?
> >>
> > It does. It shouldn't. Incrementing isn't the same as adding one, though
> > it's mathematically the same.
> In mathematics an increment is simply a (usually small) change. It need
> not be by one, and it can even be negative.
> > Incrementing means "go to the next / previous value in the set".
> In what context? I don't think it has that meaning in plain English
> (though many dictionaries, being sticklers, don't even acknowledge the
> verb), and I don't think it does in mathematics either. And in C and
> C++, incrementing means adding one.
>
Not really. Take
int *ptr;
ptr++;
You can say you are adding one to ptr, because ptr += 1 will compile to the
same machine code. But that machine code will almost certainly be
"add 4 to the address held in ptr". In fact what you mean is "go to the next value
in the sequence".
> > Adding one means "increase by a constant value which accidentally
> > happens to be unity".
> Or "increment by one" in most contexts but then I admit I don't know
> what you mean by the one being an accident.
>
Say we are doing an experiment,and we know that the does that kills the bacteria
is about 5mg, but we don't know the exact value. It would be reasonable to
conduct a series of tests: 1mg, 2mg, 3mg, 4mg, 5mg, 6mg, 7mg, 8mg, 9mg, 10mg.
Then we can measure the effective dose to a resolution of 1mg.
However the fact we are using metric units is merely conventional. It has no
scientific significance. As is our choice of 1mg as the spacing between the tests.
So it's "accidental".
On the other hand, say we've observed at two men can dig a hole faster than one man
can dig half a hole. And maybe three men are faster than two men. But clearly
there will come a point where this effect either levels off or goes into reverse. So
we set one man, two men, and so on, up to ten men, digging a hole, and time them.
Now the choice of one is not "accidental". It's fundamental that we can only have
a whole number of workers.
>
> I agree with some of these conclusions. I often choose <obj> += 1 over
> either ++<obj> or <obj>++ based on what the intended meaning is because
> I prefer to think of ++ and -- as "next" and "previous", and += as
> "increment by".
>
Exactly. ++ should mean "take the next member of an ordered set". Which it
does in C++. In C++ "++" can't always be replaced by "+=1". In C it can.
Of course in C++ the increment operator can be overloaded by the user
perversely, so we have to qualify that statement. But I don't think it is used
perversely in any C++ libraries of any traction.

Keith Thompson

unread,
Jun 27, 2022, 7:02:50 PM6/27/22
to
Malcolm McLean <malcolm.ar...@gmail.com> writes:
> On Monday, 27 June 2022 at 20:49:33 UTC+1, Ben Bacarisse wrote:
>> Malcolm McLean <malcolm.ar...@gmail.com> writes:
>>
>> > On Sunday, 26 June 2022 at 09:20:03 UTC+1, gdo...@gmail.com wrote:
>> >> Interesting ++ and— can be used on floating point values.
>> >>
>> >> Is this relatively new? Does C allow that?
>> >>
>> > It does. It shouldn't. Incrementing isn't the same as adding one, though
>> > it's mathematically the same.
>> In mathematics an increment is simply a (usually small) change. It need
>> not be by one, and it can even be negative.
>> > Incrementing means "go to the next / previous value in the set".
>> In what context? I don't think it has that meaning in plain English
>> (though many dictionaries, being sticklers, don't even acknowledge the
>> verb), and I don't think it does in mathematics either. And in C and
>> C++, incrementing means adding one.
>>
> Not really. Take

Yes, really.

> int *ptr;
> ptr++;
> You can say you are adding one to ptr, because ptr += 1 will compile to the
> same machine code.

Yes, that's what I mean. Or rather, what I mean is that it has the same
required behavior; I didn't mention machine code.

> But that machine code will almost certainly be
> "add 4 to the address held in ptr". In fact what you mean is "go to the next value
> in the sequence".

Which you do by adding 1. In pointer arithmetic, adding 1 has a well
defined meaning, which is not advancing to the next memory address.

[..]

> Say we are doing an experiment,and we know that the does that kills the bacteria
> is about 5mg, but we don't know the exact value. It would be reasonable to
> conduct a series of tests: 1mg, 2mg, 3mg, 4mg, 5mg, 6mg, 7mg, 8mg, 9mg, 10mg.
> Then we can measure the effective dose to a resolution of 1mg.
> However the fact we are using metric units is merely conventional. It has no
> scientific significance. As is our choice of 1mg as the spacing between the tests.
> So it's "accidental".
> On the other hand, say we've observed at two men can dig a hole faster than one man
> can dig half a hole. And maybe three men are faster than two men. But clearly
> there will come a point where this effect either levels off or goes into reverse. So
> we set one man, two men, and so on, up to ten men, digging a hole, and time them.
> Now the choice of one is not "accidental". It's fundamental that we can only have
> a whole number of workers.

Or say we're writing C or C++. Then incrementing means adding 1.

[...]

> Exactly. ++ should mean "take the next member of an ordered set". Which it
> does in C++. In C++ "++" can't always be replaced by "+=1". In C it can.
> Of course in C++ the increment operator can be overloaded by the user
> perversely, so we have to qualify that statement. But I don't think it is used
> perversely in any C++ libraries of any traction.

Ben Bacarisse

unread,
Jun 27, 2022, 8:15:14 PM6/27/22
to
Malcolm McLean <malcolm.ar...@gmail.com> writes:

> On Monday, 27 June 2022 at 20:49:33 UTC+1, Ben Bacarisse wrote:
>> Malcolm McLean <malcolm.ar...@gmail.com> writes:
>>
>> > On Sunday, 26 June 2022 at 09:20:03 UTC+1, gdo...@gmail.com wrote:
>> >> Interesting ++ and— can be used on floating point values.
>> >>
>> >> Is this relatively new? Does C allow that?
>> >>
>> > It does. It shouldn't. Incrementing isn't the same as adding one, though
>> > it's mathematically the same.
>> In mathematics an increment is simply a (usually small) change. It need
>> not be by one, and it can even be negative.
>> > Incrementing means "go to the next / previous value in the set".
>> In what context? I don't think it has that meaning in plain English
>> (though many dictionaries, being sticklers, don't even acknowledge the
>> verb), and I don't think it does in mathematics either. And in C and
>> C++, incrementing means adding one.
>>
> Not really.

It really does. It's right there in the definition.

> Take
> int *ptr;
> ptr++;

> You can say you are adding one to ptr, because ptr += 1 will compile
> to the same machine code. But that machine code will almost certainly
> be "add 4 to the address held in ptr". In fact what you mean is "go to
> the next value in the sequence".

What happens to the representation of the pointer when we add one to it
should not prevent you from believing that you are adding 1. You are
adding 1.

>> > Adding one means "increase by a constant value which accidentally
>> > happens to be unity".
>> Or "increment by one" in most contexts but then I admit I don't know
>> what you mean by the one being an accident.
>>
> Say we are doing an experiment,and we know that the does that kills
> the bacteria is about 5mg, but we don't know the exact value. It would
> be reasonable to conduct a series of tests: 1mg, 2mg, 3mg, 4mg, 5mg,
> 6mg, 7mg, 8mg, 9mg, 10mg. Then we can measure the effective dose to a
> resolution of 1mg. However the fact we are using metric units is
> merely conventional. It has no scientific significance. As is our
> choice of 1mg as the spacing between the tests. So it's "accidental".

Ah, scare quotes. I agree it's "accidental" but not that it's
accidental.

> On the other hand, say we've observed at two men can dig a hole faster
> than one man can dig half a hole. And maybe three men are faster than
> two men. But clearly there will come a point where this effect either
> levels off or goes into reverse. So we set one man, two men, and so
> on, up to ten men, digging a hole, and time them. Now the choice of
> one is not "accidental". It's fundamental that we can only have a
> whole number of workers.

But you said

"Adding one means "increase by a constant value which accidentally
happens to be unity".

I see neither an accident nor an "accident" here. Adding one means
increasing by unity. That seems to me to be fundamental.

>> I agree with some of these conclusions. I often choose <obj> += 1 over
>> either ++<obj> or <obj>++ based on what the intended meaning is because
>> I prefer to think of ++ and -- as "next" and "previous", and += as
>> "increment by".
>>
> Exactly. ++ should mean "take the next member of an ordered set". Which it
> does in C++.

Eh? It means add one in C++: "The value of the operand object is
modified (3.1) by adding 1 to it". What is the next member after 1.0 of
the ordered set of double values? What is ++x when x is 1.0?

> In C++ "++" can't always be replaced by "+=1". In C it can.

Eh (again)? Both standards give that equivalence so as to delegate all
the details about types and conversion to the descriptions of addition
and assignment.

> Of course in C++ the increment operator can be overloaded by the user
> perversely, so we have to qualify that statement. But I don't think it is used
> perversely in any C++ libraries of any traction.

--
Ben.

Malcolm McLean

unread,
Jun 27, 2022, 9:42:22 PM6/27/22
to
In pointer arithmetic, adding one does not mean adding one to the address.
So it's "adding one", but only if, in this context, we accept that "adding one"
means "add four" (or however many bytes an integer occupies).
ptr++ means "go to the next integer in the sequence and take its address".

You can of course also say it's "adding one" because of C's rules for
pointer arithmetic. But it's not "really adding one".
Take this.
int x;
int* iptr = &x;
unsigned char* cptr = iptr;
if (iptr == cptr)
printf("pointers the same\n");
iptr++;
cptr++;
if (iptr == cptr)
printf("pointers the same\n");

Now iptr and cptr are equal, we add the same value to them and then they are not
equal. This isn't "wrong" because we're not working with the normal rules for
arithmetic. But we're using the word "add" in a special way. So we can say "we're
not really adding one", using the normal meaning of the word.

Malcolm McLean

unread,
Jun 27, 2022, 9:53:06 PM6/27/22
to
If we've got two workers and add another, we have increased by unity.
If we've got two grams of sugar and we add another gram, we've done
something rather different.
The symbol "1" appears in both cases if you write it out. But it doesn't
mean the same thing. In one case it expresses an underlying, fundamental
property of the thing it represents. In the other case it doesn't. It expresses
an accidental property of the sugar.

Keith Thompson

unread,
Jun 27, 2022, 10:28:10 PM6/27/22
to
Yes, it does -- because that's how C and C++ define the operation of
adding a pointer and an integer.

> So it's "adding one", but only if, in this context, we accept that "adding one"
> means "add four" (or however many bytes an integer occupies).

No, adding an integer value N to a pointer value does not mean adding N
bytes (unless sizeof *ptr == 1).

> ptr++ means "go to the next integer in the sequence and take its address".

Given that ptr is of type int*, yes, more or less. (I'd phrase it
differently.)

ptr = ptr + 1 means exactly the same thing.

> You can of course also say it's "adding one" because of C's rules for
> pointer arithmetic. But it's not "really adding one".

Yes, it's really adding one.

> Take this.
> int x;
> int* iptr = &x;
> unsigned char* cptr = iptr;
> if (iptr == cptr)
> printf("pointers the same\n");
> iptr++;
> cptr++;
> if (iptr == cptr)
> printf("pointers the same\n");
>
> Now iptr and cptr are equal, we add the same value to them and then they are not
> equal. This isn't "wrong" because we're not working with the normal rules for
> arithmetic. But we're using the word "add" in a special way. So we can say "we're
> not really adding one", using the normal meaning of the word.

We're using "add" in the way defined by the language. That is the
normal meaning.

Please stop trying to confuse the issue by applying other meanings to
terms that are already well defined.

Yes, we know that some of these terms can have different meanings in
other contexts. You're insisting that those other meanings are somehow
more "normal" than the meanings defined by the language. That's silly.

Malcolm McLean

unread,
Jun 27, 2022, 11:37:57 PM6/27/22
to
It would have been more consistent for C to have defined

ptr += sizeof(*ptr);

as the way of moving a pointer along to the next position.
However it's such a common requirement that this wasn't done, and instead
the concept of "scaled arithmetic" was developed.
When you change the rules of arithmetic like this, inevitably you break some
of the relationships that hold in arithmetic over the set of the real numbers.
In this case
a = x;
b = x;
therefore a + c = b + c;
no longer necessarily holds.
So "a + c" means something different to what is normally understood by
these symbols. What is meant is sufficiently close to the operation of addition
over the real numbers to make it reasonable to use the same word, as
long as you make clear that you are using the word :add" in a special
way.

Keith Thompson

unread,
Jun 28, 2022, 2:07:17 AM6/28/22
to
No, it really wouldn't. Pointers are not numbers. It's useful to
define a few limited arithmetic operators on them:
pointer + integer -> pointer
pointer - integer -> pointer
pointer - pointer -> integer

Defining ptr+1 to yield a useless and invalid pointer would have been
silly.

Do you expect pointer+pointer or integer-pointer to have some consistent
meaning?

> However it's such a common requirement that this wasn't done, and instead
> the concept of "scaled arithmetic" was developed.
> When you change the rules of arithmetic like this, inevitably you break some
> of the relationships that hold in arithmetic over the set of the real numbers.
> In this case
> a = x;
> b = x;
> therefore a + c = b + c;
> no longer necessarily holds.

Sure it does, as long as the types are consistent. Adding 1 to an int*
pointer is a *different operation* than adding 1 to a char*.

> So "a + c" means something different to what is normally understood by
> these symbols. What is meant is sufficiently close to the operation of addition
> over the real numbers to make it reasonable to use the same word, as
> long as you make clear that you are using the word :add" in a special
> way.

It's a lot easier to understand pointer arithmitec the way it's actually
defined than to start with some inconsistent mental model and adjust it
to fit reality.

Juha Nieminen

unread,
Jun 28, 2022, 2:41:06 AM6/28/22
to
Keith Thompson <Keith.S.T...@gmail.com> wrote:
> No, it really wouldn't. Pointers are not numbers. It's useful to
> define a few limited arithmetic operators on them:
> pointer + integer -> pointer
> pointer - integer -> pointer
> pointer - pointer -> integer
>
> Defining ptr+1 to yield a useless and invalid pointer would have been
> silly.

One can think of "ptr+1" as being just syntactic sugar for "&ptr[1]".
(Technically it might not be "just syntactic sugar", but one can
think of it as such.)

Malcolm McLean

unread,
Jun 28, 2022, 5:32:34 AM6/28/22
to
That's another reason for scaled pointer arithmetic. So that you can convert
between ptr[2] and *(ptr + 2).
I'm not saying that the decision to use scaled pointer arithmetic was wrong.

I am saying that ptr += 1 is not "really" adding one to the pointer, if it is not to
a single byte type. "Really" you are adding the size of the item the pointer points
to.
You can say "a pointer is not a number", and that's true in the important exceptional
case of old x86 segment::offset pointers. But these never really worked well in
C in any case. Compilers introduced the "far" keyword to help deal with them.

My sister's address is 15. But in fact she lives in the thirteenth house in the street. All
rules for numbers don't necessarily apply for house address numbers. But they
are still called numbers.

Öö Tiib

unread,
Jun 28, 2022, 6:05:51 AM6/28/22
to
On Tuesday, 28 June 2022 at 12:32:34 UTC+3, Malcolm McLean wrote:
> On Tuesday, 28 June 2022 at 07:41:06 UTC+1, Juha Nieminen wrote:
> > Keith Thompson <Keith.S.T...@gmail.com> wrote:
> > > No, it really wouldn't. Pointers are not numbers. It's useful to
> > > define a few limited arithmetic operators on them:
> > > pointer + integer -> pointer
> > > pointer - integer -> pointer
> > > pointer - pointer -> integer
> > >
> > > Defining ptr+1 to yield a useless and invalid pointer would have been
> > > silly.
> > One can think of "ptr+1" as being just syntactic sugar for "&ptr[1]".
> > (Technically it might not be "just syntactic sugar", but one can
> > think of it as such.)
> >
> That's another reason for scaled pointer arithmetic. So that you can convert
> between ptr[2] and *(ptr + 2).

It is other way around. The operator [] is defined in terms of pointer arithmetic
so 2[ptr] is *(2 + ptr) and so required to work. We can't have circular definitions
in specification.

> I'm not saying that the decision to use scaled pointer arithmetic was wrong.
>
> I am saying that ptr += 1 is not "really" adding one to the pointer, if it is not to
> a single byte type. "Really" you are adding the size of the item the pointer points
> to.

IOW you see yourself that making it in any other way would be silly. Pointer
is internally address but that is not exposed in its interface.

> You can say "a pointer is not a number", and that's true in the important exceptional
> case of old x86 segment::offset pointers. But these never really worked well in
> C in any case. Compilers introduced the "far" keyword to help deal with them.

You need to use reinterpret_cast to get the integer value of that address out
of pointer, or to turn it into byte address ... and then you need to know what
platform you are at and what you are doing.

Malcolm McLean

unread,
Jun 28, 2022, 6:15:28 AM6/28/22
to
On Tuesday, 28 June 2022 at 11:05:51 UTC+1, Öö Tiib wrote:
> On Tuesday, 28 June 2022 at 12:32:34 UTC+3, Malcolm McLean wrote:
> > On Tuesday, 28 June 2022 at 07:41:06 UTC+1, Juha Nieminen wrote:
> > > Keith Thompson <Keith.S.T...@gmail.com> wrote:
> > > > No, it really wouldn't. Pointers are not numbers. It's useful to
> > > > define a few limited arithmetic operators on them:
> > > > pointer + integer -> pointer
> > > > pointer - integer -> pointer
> > > > pointer - pointer -> integer
> > > >
> > > > Defining ptr+1 to yield a useless and invalid pointer would have been
> > > > silly.
> > > One can think of "ptr+1" as being just syntactic sugar for "&ptr[1]".
> > > (Technically it might not be "just syntactic sugar", but one can
> > > think of it as such.)
> > >
> > That's another reason for scaled pointer arithmetic. So that you can convert
> > between ptr[2] and *(ptr + 2).
> It is other way around. The operator [] is defined in terms of pointer arithmetic
> so 2[ptr] is *(2 + ptr) and so required to work. We can't have circular definitions
> in specification.
>
I don't know exactly what Denis Ritchie was thinking.
But I suspect he decided early on that [] would be the subscript operator, and that
incrementing the subscript by one would move to the next item in the array.
The last was a no-brainer.

Then you've got the question of how ptr[i] relates to *(ptr + i). Did he decide that
arrays would be 0-based, then decide that pointer arithmetic would be scaled?
Or did he decide that *(ptr + i) would mean ptr[i], and then accept, maybe reluctantly,
that that entailed 0-based arrays? I don't know.

David Brown

unread,
Jun 28, 2022, 9:08:00 AM6/28/22
to
On 28/06/2022 11:32, Malcolm McLean wrote:
> On Tuesday, 28 June 2022 at 07:41:06 UTC+1, Juha Nieminen wrote:
>> Keith Thompson <Keith.S.T...@gmail.com> wrote:
>>> No, it really wouldn't. Pointers are not numbers. It's useful to
>>> define a few limited arithmetic operators on them:
>>> pointer + integer -> pointer
>>> pointer - integer -> pointer
>>> pointer - pointer -> integer
>>>
>>> Defining ptr+1 to yield a useless and invalid pointer would have been
>>> silly.
>> One can think of "ptr+1" as being just syntactic sugar for "&ptr[1]".
>> (Technically it might not be "just syntactic sugar", but one can
>> think of it as such.)
>>
> That's another reason for scaled pointer arithmetic. So that you can convert
> between ptr[2] and *(ptr + 2).
> I'm not saying that the decision to use scaled pointer arithmetic was wrong.
>
> I am saying that ptr += 1 is not "really" adding one to the pointer, if it is not to
> a single byte type. "Really" you are adding the size of the item the pointer points
> to.
> You can say "a pointer is not a number", and that's true in the important exceptional
> case of old x86 segment::offset pointers. But these never really worked well in
> C in any case. Compilers introduced the "far" keyword to help deal with them.

You are wrong. A pointer is /not/ a number. It is /not/ an address.
If you find that confusing, then it is no wonder you are writing such a
stream of muddled posts.

As a general definition, a "pointer" is a way to access data indirectly.

In C, it is basically "an address with type information". (I say
basically, because it can also represent information about what may or
may not be accessible as fully defined behaviour, and of course weird
implementations can have other data in a pointer.) In C++, that applies
to "raw" pointers - other kinds of pointers may have extra information.

If "p" is a pointer, p++ adds 1 to the /pointer/. It does not
necessarily add 1 to the address stored by the pointer - we very rarely
care what happens under the hood.


If "p" and "q" are two pointers, and "n" is an integer, then it is
always the case in C that "p + n == q + n", as you would expect. That
is because the expression makes no sense in the language if "p" and "q"
point to incompatible types, and the compiler should reject the code
with an error if they are not compatible.


It is important to understand the difference between what a high-level
concept like "pointer" represents, and how it might happen to be
implemented in a particular case - even if the implementation is obvious
and close to universal.

David Brown

unread,
Jun 28, 2022, 9:17:31 AM6/28/22
to
On 27/06/2022 23:32, Malcolm McLean wrote:
> On Monday, 27 June 2022 at 20:49:33 UTC+1, Ben Bacarisse wrote:
>> Malcolm McLean <malcolm.ar...@gmail.com> writes:
>>
>>> On Sunday, 26 June 2022 at 09:20:03 UTC+1, gdo...@gmail.com wrote:
>>>> Interesting ++ and— can be used on floating point values.
>>>>
>>>> Is this relatively new? Does C allow that?
>>>>
>>> It does. It shouldn't. Incrementing isn't the same as adding one, though
>>> it's mathematically the same.
>> In mathematics an increment is simply a (usually small) change. It need
>> not be by one, and it can even be negative.
>>> Incrementing means "go to the next / previous value in the set".
>> In what context? I don't think it has that meaning in plain English
>> (though many dictionaries, being sticklers, don't even acknowledge the
>> verb), and I don't think it does in mathematics either. And in C and
>> C++, incrementing means adding one.
>>
> Not really.

As Ben and Keith have said, it is in the definition in the C standards.
(In C++, is always possible to have different effects on operators of
your own types - but the same definition applies in C++ for the built-in
integer, floating point and raw pointer types.)


To quote from C11 :

(6.5.2.4)
"""
The result of the postfix ++ operator is the value of the operand. As a
side effect, the value of the operand object is incremented (that is,
the value 1 of the appropriate type is added to it). See the discussions
of additive operators and compound assignment for information on
constraints, types, and conversions and the effects of operations on
pointers.

The postfix -- operator is analogous to the postfix ++ operator, except
that the value of the operand is decremented (that is, the value 1 of
the appropriate type is subtracted from it).
"""

(6.5.3.1)
"""
The value of the operand of the prefix ++ operator is incremented. The
result is the new value of the operand after incrementation. The
expression ++E is equivalent to (E+=1).

See the discussions of additive operators and compound assignment for
information on constraints, types, side effects, and conversions and the
effects of operations on pointers.

The prefix -- operator is analogous to the prefix ++ operator, except
that the value of the operand is decremented.
"""







Ben Bacarisse

unread,
Jun 28, 2022, 9:55:46 AM6/28/22
to
You can't do either in C++. In C++ you manipulate numerical quantities,
and unity is 1 when talking about numerical values. In C++ I'd write

workers += 1;
grams_of_sugar += 1;

I have added 1 in both cases and there is nothing accidental about
that. It was done (presumably) because that is what the program design
needs at this point.

> The symbol "1" appears in both cases if you write it out. But it
> doesn't mean the same thing. In one case it expresses an underlying,
> fundamental property of the thing it represents. In the other case it
> doesn't. It expresses an accidental property of the sugar.

I know what you are getting at, but in C++ adding unity means adding
one. The fact that we designed the program so that adding one was the
right thing to do at that point was not an accident though they may have
been some choice in the matter. The fact that some quantities are
dimensionless does not justify saying that in the other cases adding one
(in a program) is an accident.

I hope you can see I know what you are getting at. It's the words I
don't like. It gives rise to statements that appear daft to me. I
don't mind "accidental" because the scare quotes tell me you don't mean
a literal accident.

--
Ben.

Malcolm McLean

unread,
Jun 28, 2022, 10:22:26 AM6/28/22
to
A pointer is a way to access data indirectly.
But so is a reference.
So is a key.

But references and keys are not pointers.
In C and C++, it must be possible to take the address past the pointer.
Even in the case of a pointer to a scalar.
So a pointer does have to be an "address". Usually, a machine address of
course. In exceptional implementations you might want to argue about
what constitutes an "address" and what doesn't. But you must be able to
"go to the next address", so it's got to have number-like properties. It
can't be any system of indirection.

David Brown

unread,
Jun 28, 2022, 11:23:40 AM6/28/22
to
So what? References are handled differently - you can't increment a
reference in C++, you can only change the object it references. And
"key" has no definition or meaning in the language.

When you increment something in C++, using the operators and types that
are part of the core language rather than any user definition on user
types, you are adding 1 to it. It is /that/ simple. I quoted the
passages from the C standards - you can look up the C++ standards
yourself and find something very similar.

When you are in a hole - and you are very much in a hole - stop digging.
If you find it hard to understand how pointer arithmetic works in the
language, ask - and surely someone will try to help you. But please
stop rambling about other things in an attempt to make it look like the
situation is complicated, or vague in some way. It is /simple/ -
"increment" in C and C++ means "adding 1".

<snip more unrelated, irrelevant confusion>

Keith Thompson

unread,
Jun 28, 2022, 2:12:05 PM6/28/22
to
You've obviously made up your mind.

No, pointers are not numbers.

Yes, ptr += 1 *really* adds one to ptr, based on what "add" is defined
to mean in this context.

Similar reasoning would say that
double x = 1.0;
x += 1.0;
isn't *really* adding one to x because it doesn't increment the last bit
of its representation.

For house numbers, we explicitly use numbers as the human-visible
representation. For pointers, we don't; the output you can get with
`printf("%p\n", ptr)` is incidental, not fundamental to the way we deal
with them. Insisting on thinking of pointers as numbers will only lead
to confusion.

Keith Thompson

unread,
Jun 28, 2022, 2:14:57 PM6/28/22
to
David Brown <david...@hesbynett.no> writes:
[...]
> You are wrong. A pointer is /not/ a number. It is /not/ an
> address. If you find that confusing, then it is no wonder you are
> writing such a stream of muddled posts.
[...]

One small quibble: An "address" in C or C++ is a pointer value. Like
any value, it implicitly includes type information.

The word "address" is also used to refer to a raw machine-level address,
which is the usual representation of a pointer value but is conceptually
different.

Malcolm McLean

unread,
Jun 28, 2022, 6:12:18 PM6/28/22
to
Well we've got an immediate contradiction there.
Pointers are not numbers.
But ptr += 1 *really* adds one to ptr.

However addition is defined as an operation on two numbers.
Of course you can say that "add doesn't mean that in this context`'.
Fair enough.
But then it's not *really* addition.


Keith Thompson

unread,
Jun 28, 2022, 7:13:13 PM6/28/22
to
*sigh*

You claim that "addition is defined as an operation on two numbers".

Defined by whom? Would you like to *add* a source for that claim?

You can add things other than numbers. Addition on pointers is defined
by the standard for the language that we discuss in this newsgroup.

Yes, it really is addition.

Öö Tiib

unread,
Jun 28, 2022, 9:16:07 PM6/28/22
to
It *really* is. Consider real life physical thing like time. There is
time point and time duration.
You can not add two time points, it does not make sense. But
you can add duration to point to get new point or you can subtract
one point from other to get duration. Exactly same is going on
with pointers and it is purely logical.

Malcolm McLean

unread,
Jun 29, 2022, 2:14:56 AM6/29/22
to
That is a good point.
Except that your two time points really have to be defined as a delta to a
general reference point.
You can't subtract teatime from bedtime unless you know that teatime
is five O"clock and bed time is 8 O'clock. That's defined relative to midnight,
then the day is defined on the calendar relative to the birth of Christ.

But the reference point is an event, not a number. Fair enough.

Similarly, a pointer can't be "a location of memory" defined anyhow.
It might contain a non-number, for example you could have the "fast"
memory and the 'slow" memory, distinguished by "F" and "S" in the pointer.
But the pointer has to be a delta from some point in the fast, for example,
memory.
So a pointer has to contain a number. It can carry additional information.
But it has to contain a number. Unlike a "key" which can be anything which
can ultimately be decoded to a data location.

Now addition on the deltas (the number in the pointer) is defined in the same
way as addition over the integers. But C++ pointer arithmetic isn't defined
in this way. It's defined in terms of "taking the location of next object of the
same type in memory" . Usually of course that means that the addition operation
on the number contained within the pointer is scaled by the number of bytes.
It's doesn't absolutely have to be this, of course (not all machines have CHAR_BIT
resolution hardware address registers). Virtually always the simple relationship
holds. Always the addition operation on the number in the pointer is scaled in
some manner determined by the size of the object pointed to.

Now you can understand what is going on in two ways. You can say "this isn't
really addition. We've changed the rules." or if you want to insist that it is
"really addition". Then "it is *really* addition but you in your ignorance don't
know what addition means. It means something special in C++."
But I'd say that that is a confusing way of trying to understand things. It's
maybe logically tenable, but it's not very sensible.

A better way of understanding things is to say that "pointer arithmetic is
really addition. There's a number in the pointer which is really manipulated
according to the laws of normal integer arithmetic. But 1 isn't "really" one.
It's scaled by the size of the object pointed to."

Juha Nieminen

unread,
Jun 29, 2022, 5:08:11 AM6/29/22
to
Keith Thompson <Keith.S.T...@gmail.com> wrote:
> Yes, ptr += 1 *really* adds one to ptr, based on what "add" is defined
> to mean in this context.

It's confusing when you word it like that. Even if what you say may be
technically correct, it easily makes people misunderstand what it's doing.

Maybe it should be better to say that "ptr+=1 advances the pointer by
one element" (and thus eg. "ptr+=5 advances the pointer by 5 elements").

"Advance by one (element)" is less confusing than "add one".

Öö Tiib

unread,
Jun 29, 2022, 8:50:51 AM6/29/22
to
The number is there in address to abstract the issue of all the traffic between
three layers of cache, physical memory and page file away from compiler
or interpreter. The increments of more than 1 of that address are there because
programmers want 5th Monkey in array after what the pointer currently points
at. Typical Python or JavaScript programmer may sometimes to think about
page file or cache, but it is rarely fruitful.

Way more complex is time. There is difference if we represent the duration
in weeks, hours or in months. These are not constant amounts of Planck
time units and there is imprecise relation in those to each other. But we
have to use all in our bookkeeping if we agreed to pay salary to someone
at 10 am (daylight saving taken into account) first working day after 4th
of next month that they did their work. So typical bookkeeper or
businessman may sometimes to think about Planck time units but it is
rarely fruitful.

Malcolm McLean

unread,
Jun 29, 2022, 10:59:27 AM6/29/22
to
Memory has to be a whole number of bits. The bits don't have to be identical, but
they do have to be identical in terms of what data they can represent. So
indexing them by number is the obvious approach. C requires a successor function
for valid pointers, so basically that constrains pointers to be numbers, though not
strictly.
>
> Way more complex is time. There is difference if we represent the duration
> in weeks, hours or in months. These are not constant amounts of Planck
> time units and there is imprecise relation in those to each other. But we
> have to use all in our bookkeeping if we agreed to pay salary to someone
> at 10 am (daylight saving taken into account) first working day after 4th
> of next month that they did their work. So typical bookkeeper or
> businessman may sometimes to think about Planck time units but it is
> rarely fruitful.
>
Except maybe in experiments in fundamental physics, you can't measure
time accurately. And for practical purposes it is continuous and one-dimensional.
But the units aren't always defined in strictly compatible ways. If you
define "day" the Jewish way, sundown to sundown, then the days aren't
quite 24 hours, for example. However "ten days" is still a well-defined period
of time. It's just not defined in terms of seconds.

Öö Tiib

unread,
Jun 29, 2022, 10:30:44 PM6/29/22
to
Memory does not need to exist at all, as long as underlying system provides
it just in time when program tries to access it the program may live in naive
illusion of having fair chunk of continuous memory under control. The issue
of how it is actually physically arranged is abstracted away from program
with those continuous numbers of addresses.

> >
> > Way more complex is time. There is difference if we represent the duration
> > in weeks, hours or in months. These are not constant amounts of Planck
> > time units and there is imprecise relation in those to each other. But we
> > have to use all in our bookkeeping if we agreed to pay salary to someone
> > at 10 am (daylight saving taken into account) first working day after 4th
> > of next month that they did their work. So typical bookkeeper or
> > businessman may sometimes to think about Planck time units but it is
> > rarely fruitful.
> >
> Except maybe in experiments in fundamental physics, you can't measure
> time accurately. And for practical purposes it is continuous and one-dimensional.
> But the units aren't always defined in strictly compatible ways. If you
> define "day" the Jewish way, sundown to sundown, then the days aren't
> quite 24 hours, for example. However "ten days" is still a well-defined period
> of time. It's just not defined in terms of seconds.

Ten days is usually 240 hours, but sometimes 239 and sometimes 241 hours
in most countries.

Malcolm McLean

unread,
Jun 30, 2022, 6:10:02 AM6/30/22
to
You could have some weird and wonderful system whereby you manufacture
memory on demand. However the request has to be a whole number of bits.
In C, it has to be a whole number of bytes.
>
> Ten days is usually 240 hours, but sometimes 239 and sometimes 241 hours
> in most countries.
>
A Jewish day is sundown to sundown. So it's never a whole number of hours,
because the time from midnight to sundown is slightly different due to
days getting longer or shorter.

wij

unread,
Jun 30, 2022, 8:24:07 AM6/30/22
to
Think of the early days of C, The basic goal is a 'portable assembly'.
IIRC, ptr+1 has to (sort of) mean pointing to the next element in an array,
otherwise it won't be portable. As it means to be portable, less related to
hardware.
The point here is that users interpretation/taste has to be implementable.

Ben Bacarisse

unread,
Jun 30, 2022, 10:03:57 AM6/30/22
to
I don't think this description matches the facts as reported by DMR
himself. I don't think there was ever a goal to design a "portable
assembly". The main goal for early C was to add types to B so that it
would be more convenient on byte-addressed machines.

> As it means to be portable, less related to hardware.

So, yes, portability was the motivating factor, but the meaning given to
pointer+1 was almost certainly picked so that B programmers would find
array manipulation familiar.

--
Ben.

Alf P. Steinbach

unread,
Jun 30, 2022, 3:24:04 PM6/30/22
to
On 30 Jun 2022 16:03, Ben Bacarisse wrote:
>
> [snip]
> I don't think there was ever a goal to design a "portable
> assembly". The main goal for early C was to add types to B so that it
> would be more convenient on byte-addressed machines.

For the literal term "portable assembly" DMR only notes that C is /used/
that way as the output of some compiler for other languages; <url:
https://www.bell-labs.com/usr/dmr/www/chist.html>. I know of one modern
such compiler, namely Eiffel. Or, it was that way early 2000's.

However, while DMR does not directly use the term "portable assembly"
about the C design goals, he describes it as providing a portable
replacement for the assembly code then used for the Unix implementation.
So regarding the design goal "portable assembly" makes sense as a
descriptive term. A portable replacement for machine specific assembly.

Unix was rewritten in mostly C in 1973. That's from old "The Unix
Programming Environment", I discovered [tears] that I've apparently lost
my old dead wood copy. But I have two PDFs of it.


>> As it means to be portable, less related to hardware.
>
> So, yes, portability was the motivating factor, but the meaning given to
> pointer+1 was almost certainly picked so that B programmers would find
> array manipulation familiar.

DMR's C history paper notes that at first pointers were much like in
BCPL, namely just indices into arrays!, and that `unsigned` types were
added to C to more separate pointers from integers.

Learned today: that there was a short-lived little language called NB in
between B and C, so it's BCPL -> B -> NB -> C.


- Alf

Ben Bacarisse

unread,
Jun 30, 2022, 7:29:15 PM6/30/22
to
"Alf P. Steinbach" <alf.p.s...@gmail.com> writes:

> On 30 Jun 2022 16:03, Ben Bacarisse wrote:
>> [snip]
>> I don't think there was ever a goal to design a "portable
>> assembly". The main goal for early C was to add types to B so that it
>> would be more convenient on byte-addressed machines.
>
> For the literal term "portable assembly" DMR only notes that C is
> /used/ that way as the output of some compiler for other languages;
> <url: https://www.bell-labs.com/usr/dmr/www/chist.html>. I know of one
> modern such compiler, namely Eiffel. Or, it was that way early 2000's.
>
> However, while DMR does not directly use the term "portable assembly"
> about the C design goals, he describes it as providing a portable
> replacement for the assembly code then used for the Unix
> implementation. So regarding the design goal "portable assembly" makes
> sense as a descriptive term. A portable replacement for machine
> specific assembly.

Agreed. C was always intended to be low-level enough to make writing
assembly code largely redundant.

Bit thinking of C as a "portable assembler" does much more harm than
good. The idea leads many beginners astray.

> Learned today: that there was a short-lived little language called NB
> in between B and C, so it's BCPL -> B -> NB -> C.

Really CPL -> BCPL -> B -> NB -> C since BCPL is a basic version of CPL.

BCPL and B were relatively long lived. I used B in 1980, though it was
on it's last legs by then. BCPL was used in anger right up into the
1990s, and it still usable today. CPL barely happened at all and
despite being the inspiration for BCPL, it wasn't implemented until
after BCPL. NB was genuinely just a transitional development and had no
life of it's own.

If you like the idea of a relatively modern typeless programming
language you might be interested in MCPL, an offshoot of BCPL.

--
Ben.

David Brown

unread,
Jul 1, 2022, 3:10:51 AM7/1/22
to
On 30/06/2022 21:23, Alf P. Steinbach wrote:
> On 30 Jun 2022 16:03, Ben Bacarisse wrote:
>>
>> [snip]
>> I don't think there was ever a goal to design a "portable
>> assembly".  The main goal for early C was to add types to B so that it
>> would be more convenient on byte-addressed machines.
>
> For the literal term "portable assembly" DMR only notes that C is /used/
> that way as the output of some compiler for other languages; <url:
> https://www.bell-labs.com/usr/dmr/www/chist.html>. I know of one modern
> such compiler, namely Eiffel. Or, it was that way early 2000's.
>
> However, while DMR does not directly use the term "portable assembly"
> about the C design goals, he describes it as providing a portable
> replacement for the assembly code then used for the Unix implementation.

Yes, that is all accurate.


> So regarding the design goal "portable assembly" makes sense as a
> descriptive term. A portable replacement for machine specific assembly.
>

The danger with using "portable assembly" as a term in connection with C
is that so many people misunderstand it. As you wrote (and quoted)
earlier, C is a portable /alternative/ to assembly. It is not a
portable assembly. You can use C for low-level systems coding that was
previously the domain of assembly - and when doing so, the C code is
usually not portable at all. But it is vital to understand key
differences between assembly languages and C :

1. Assembly is defined in terms of the hardware, C is defined in terms
of a high-level abstract machine (with some flexibility to fit hardware
better).

2. Assembly is a list of commands, and the generated code follows them
closely (some assemblies have minor modifications during the process).
C is also an imperative language, but does not require the results to
follow the source code as long as the defined end result is the same.

3. Assembly synchronises the "abstract machine" of the language, and the
hardware of the processor, at pretty much every line of code. In C,
they only need to be synchronised at points of "observable behaviour".



Malcolm McLean

unread,
Jul 1, 2022, 6:53:30 AM7/1/22
to
On Friday, 1 July 2022 at 08:10:51 UTC+1, David Brown wrote:
> On 30/06/2022 21:23, Alf P. Steinbach wrote:
> > On 30 Jun 2022 16:03, Ben Bacarisse wrote:
> >>
> >> [snip]
> >> I don't think there was ever a goal to design a "portable
> >> assembly". The main goal for early C was to add types to B so that it
> >> would be more convenient on byte-addressed machines.
> >
> > For the literal term "portable assembly" DMR only notes that C is /used/
> > that way as the output of some compiler for other languages; <url:
> > https://www.bell-labs.com/usr/dmr/www/chist.html>. I know of one modern
> > such compiler, namely Eiffel. Or, it was that way early 2000's.
> >
> > However, while DMR does not directly use the term "portable assembly"
> > about the C design goals, he describes it as providing a portable
> > replacement for the assembly code then used for the Unix implementation.
> Yes, that is all accurate.
> > So regarding the design goal "portable assembly" makes sense as a
> > descriptive term. A portable replacement for machine specific assembly.
> >
> The danger with using "portable assembly" as a term in connection with C
> is that so many people misunderstand it. As you wrote (and quoted)
> earlier, C is a portable /alternative/ to assembly. It is not a
> portable assembly. You can use C for low-level systems coding that was
> previously the domain of assembly - and when doing so, the C code is
> usually not portable at all. But it is vital to understand key
> differences between assembly languages and C :
>
"Portable assembly" is a virtual oxymoron. "Portable" means "works correctly
irrespective of the machine code", whist "assembly" means "specifies the
machine code in both human and computer readable form". You can't
fulfil both requirements. However most people understand that.
>
> 1. Assembly is defined in terms of the hardware, C is defined in terms
> of a high-level abstract machine (with some flexibility to fit hardware
> better).
>
But C has some looseness in that you can inspect pointers, which in practice
hold the same bits that the processor uses to address memory.
>
> 2. Assembly is a list of commands, and the generated code follows them
> closely (some assemblies have minor modifications during the process).
> C is also an imperative language, but does not require the results to
> follow the source code as long as the defined end result is the same.
>
It doesn't require it. But usually it's possible to write a conforming C compiler
in which each C construct maps simply onto another machine code construct.
The main difference is that a C compiler can optimise poorly written or human
rather than computer meaningful code to produce more efficient machine code.
If an assembler does this, you've got to ask whether it is really still an assembler.
>
> 3. Assembly synchronises the "abstract machine" of the language, and the
> hardware of the processor, at pretty much every line of code. In C,
> they only need to be synchronised at points of "observable behaviour".
>
That's another way of saying the same thing. However you can't solve the halting
problem. In reality there are limits to how far you can translate one sequence of
imperative instructions into another, equivalent sequence of imperative instructions,
without points of synchronisation in which the logical state is the same.

David Brown

unread,
Jul 1, 2022, 8:49:22 AM7/1/22
to
I agree that it is an oxymoron. And while many C (and C++) programmers
understand that, some do not - they really do think that C is, was,
should be, or should have been "portable assembly".

>>
>> 1. Assembly is defined in terms of the hardware, C is defined in terms
>> of a high-level abstract machine (with some flexibility to fit hardware
>> better).
>>
> But C has some looseness in that you can inspect pointers, which in practice
> hold the same bits that the processor uses to address memory.

Yes, but much of what you can do with them is implementation dependent
(and therefore not very portable), or undefined behaviour (and /might/
do something you find useful, but your should consider your code tied to
exactly the compiler, target, version and options that you have used in
testing).

>>
>> 2. Assembly is a list of commands, and the generated code follows them
>> closely (some assemblies have minor modifications during the process).
>> C is also an imperative language, but does not require the results to
>> follow the source code as long as the defined end result is the same.
>>
> It doesn't require it. But usually it's possible to write a conforming C compiler
> in which each C construct maps simply onto another machine code construct.

If you write such a compiler, then you could possible argue that the
/compiler/ could be used as a kind of high-level assembler. But the
existence of such a compiler does not affect the C language - as long as
you can make a conforming C compiler which does /not/ do such simple
translation, C is not a "portable assembler".

> The main difference is that a C compiler can optimise poorly written or human
> rather than computer meaningful code to produce more efficient machine code.
> If an assembler does this, you've got to ask whether it is really still an assembler.
>>
>> 3. Assembly synchronises the "abstract machine" of the language, and the
>> hardware of the processor, at pretty much every line of code. In C,
>> they only need to be synchronised at points of "observable behaviour".
>>
> That's another way of saying the same thing.

I don't think so, but they are certainly related.

> However you can't solve the halting
> problem.

What does that have to do with anything?

> In reality there are limits to how far you can translate one sequence of
> imperative instructions into another, equivalent sequence of imperative instructions,
> without points of synchronisation in which the logical state is the same.

No, there are no such limits. Any one given compiler may have limits to
its optimisations, and it may get harder and harder to write new
optimisations which then give smaller and smaller increases in
efficiency. But there is no hard limit - real, practical, or
theoretical. You can't make a compiler that always produces the
optimally efficient results for any input (the proof of that claim is
left as an exercise for the reader), but there is not a specific limit
point.

Malcolm McLean

unread,
Jul 1, 2022, 9:56:40 AM7/1/22
to
Lets say foo is a pure function.

Now take this program

int main()
{
if (foo(42))
printf("True\n");
else
printf("False\n"):
return 0;
}

if foo(42) returns non-zero, an optimising compiler can optimise this to
"Output True".
But only if it can solve the halting problem for foo. Which you can for a simple
foo, but not in the general case. In practice only if foo is something trivial, like "iseven".


> > In reality there are limits to how far you can translate one sequence of
> > imperative instructions into another, equivalent sequence of imperative instructions,
> > without points of synchronisation in which the logical state is the same.
> No, there are no such limits. Any one given compiler may have limits to
> its optimisations, and it may get harder and harder to write new
> optimisations which then give smaller and smaller increases in
> efficiency. But there is no hard limit - real, practical, or
> theoretical. You can't make a compiler that always produces the
> optimally efficient results for any input (the proof of that claim is
> left as an exercise for the reader), but there is not a specific limit
> point.
>
Yes, but the optimisation problem reduces to the halting problem and vice
versa. There's no specific instance that you can't optimise to the maximum
theoretical limit of providing the requested output, but you can't solve it
for the general case, in theory, and you can't solve it for anything but simple
cases in practice.

jak

unread,
Jul 1, 2022, 11:17:53 AM7/1/22
to
Some time ago I thought it would be useful to me to have the possibility
of being able to choose the deviation step of ++ and - in C. for example
making the last used by the operator += (or -=)as a current deviation.

example:

int i = 2;

for(i -= 2; i < 10; i++)
{
printf("%d", i);
}

output: 0 2 4 6 8

or:

float f = 0.;
f += .25;
f++;
printf("%f", f);

output: 0.5

David Brown

unread,
Jul 1, 2022, 11:21:31 AM7/1/22
to
Nonsense. In order to optimise the branch on the result of "foo(42)",
the compiler needs to determine the result of that particular function
on that particular value. It doesn't need to "solve the halting
problem", or even solve it for that particular function. You've said
the function is "pure" - that makes it easier in many cases.

And if "foo" is a hard calculation, then knowing that it halts or not is
not sufficient for the compiler - it needs to know the actual answer (as
a boolean).

>
>>> In reality there are limits to how far you can translate one sequence of
>>> imperative instructions into another, equivalent sequence of imperative instructions,
>>> without points of synchronisation in which the logical state is the same.
>> No, there are no such limits. Any one given compiler may have limits to
>> its optimisations, and it may get harder and harder to write new
>> optimisations which then give smaller and smaller increases in
>> efficiency. But there is no hard limit - real, practical, or
>> theoretical. You can't make a compiler that always produces the
>> optimally efficient results for any input (the proof of that claim is
>> left as an exercise for the reader), but there is not a specific limit
>> point.
>>
> Yes, but the optimisation problem reduces to the halting problem and vice
> versa. There's no specific instance that you can't optimise to the maximum
> theoretical limit of providing the requested output, but you can't solve it
> for the general case, in theory, and you can't solve it for anything but simple
> cases in practice.

The halting problem - the existence of a function that will determine
the halting status of any given finite program, within finite time - is
provable false. It is therefore equivalent to any other false
statement. If we had a solution to the halting problem, we could use it
to build a perfect optimiser - and also to prove that 1 is equal to 0.
Equally, you could take a perfect compiler and use it to generate a
halting problem as well as to prove that 0 is equal to 1.

If you find it helpful to think that the "perfect compiler problem" is
equivalent to the halting problem, then I guess that's fair enough. I
don't see it bringing in any great insights, especially to the original
point about C not being a "portable assembly" - it merely muddles the
waters.

Richard Damon

unread,
Jul 1, 2022, 4:57:12 PM7/1/22
to
But sometimes it doesn't need to know if the calculation will actually
halt, as I thought there was a rule that any loop that doesn't have an
actual constant condition could be presumed to eventually end, so if a
loop has no observable effects, it can be optimized away. This has
broken many a benchmark when the code under test just gets optimized away.

Thus, if foo can be proven to return a non-zero number anytime it
returns (or always a zer0) then the if can be optimized.

Malcolm McLean

unread,
Jul 1, 2022, 5:28:25 PM7/1/22
to
You're right. The halting problem is really the "state" problem. There's
nothing special about the halt state, except that no other states are reachable
from it. The state problem can be trivially converted to the halting problem
by declaring the state in question to be a "halt" state.

Dpending how we model the mapping of a C program to a Turing machine,
the question of whether foo returns 1 or 0 can be recast as a state problem.
In one state, the return value is 1, in another, it is zero.

So in fact the "foo return problem" is identical to the halting problem,
except that we've given different labels to the states.

wij

unread,
Jul 2, 2022, 7:18:52 AM7/2/22
to
Why your questions are all like programming beginner's question (even worse
in this "ptr+1" case), in a way like olcott's: many things have to fit into what you
thought while a little analysis would reveal some fundamental logic error, or
lack of programming experiences.

Malcolm McLean

unread,
Jul 2, 2022, 1:34:50 PM7/2/22
to
foo is a pure function, written in C, which is passed a constant and returns either
1 or 0. So it can be recast as a Turing machine problem with the constant on
the tape and including two states indicating "return 1" or "return 0".
So the question now becomes, does it actually reach the "return 1 state?".
Obviously the answer must be "yes" or "no", and the call can be optimised
to to single boolean value.

But writing an algorithm to determine whether the "return 1" state is reached
or not is exactly the same problem as writing an algorithm to determine
whether the "halt' state is reached or not. All that has changed is the label
given to the state.

To be fair, there is one slight difference - if we can prove that the "return 0"
state is reached, then we know a priori that "return 1" is unreachable.
But that's not enough to change the basic point.

James Kuyper

unread,
Jul 5, 2022, 11:50:45 PM7/5/22
to
On 7/1/22 16:56, Richard Damon wrote:
...
> But sometimes it doesn't need to know if the calculation will actually
> halt, as I thought there was a rule that any loop that doesn't have an
> actual constant condition could be presumed to eventually end, so if a
> loop has no observable effects, it can be optimized away. This has
> broken many a benchmark when the code under test just gets optimized away.

I think the rule you're thinking of is the following:

"An iteration statement may be assumed by the implementation to
terminate if its controlling expression is not a constant expression,
171) and none of the following operations are performed in its body,
controlling expression or (in the case of a for statement) its
expression-3: 172)
— input/output operations
— accessing a volatile object
— synchronization or atomic operations."

However, that rule is from the C standard (6.8.5p6), and I did not
locate corresponding text in the C++ standard.
0 new messages