Friday, May 24, 2019

Digest for comp.lang.c++@googlegroups.com - 25 updates in 3 topics

Keith Thompson <kst-u@mib.org>: May 23 04:29PM -0700

>>level language" and what is a "low level language", so any discussion is
 
> Prolog or F# are high level languages. There is a clear logical abstraction
> between the CPU and the code. There is no such abstraction with C.
 
Of course some languages are at a higher level than others, and C is at
a lower level than most non-assembly languages. But as I see it, the
biggest gap is between assembly languages, where each program specifies
a sequence of instructions for a particular CPU, and non-assembly
languages (including C), where each program specifies run-time behavior.
 
C most certainly does provide an abstraction between the CPU and code.
If you write
 
int a = 10;
int b = 20;
int c = a + b;
 
(in C or C++), that says *nothing* about which CPU instructions will
be generated. It says only that the generated code must implement
implement the specified run-time behavior. There needn't even be
an ADD instruction; a compiler could simply generate code to store
30 in c, or omit it altogether if the value is never used.
 
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
Bart <bc@freeuk.com>: May 24 01:45AM +0100

On 24/05/2019 00:29, Keith Thompson wrote:
> a lower level than most non-assembly languages. But as I see it, the
> biggest gap is between assembly languages, where each program specifies
> a sequence of instructions for a particular CPU,
 
It's not really about specific instructions, which are not of great
interest, but being to specify what you want in more detail and without
interference.
 
Yes, the HLL will provide a different mapping to ASM instructions
depending on datatypes for example. That is convenient; what isn't so
convenient is a HLL language deciding that what would be a very
ordinary, harmless sequence of ASM:
 
mov dword [R],1234.0
mov dword [R],1234
 
is undefined behaviour. I don't think C is at a high enough level or
smart enough to decide that for me. You need to be able to do some
underhand things with this kind of language without /having/ to use ASM,
and without having to tie yourself up in knots getting around the language.
 
C should stick to concerning itself with which sequence the "+" in "a+b"
is mapped to:
 
add al,bl
add rax,rbx
addsd xmm0,xmm1
lea rax,[rax+rbx*4]
call add128
call addstring ; this is C++ after all
 
and leave the bigger decisions to the programmer, who will be using this
kind of language for a reason.
Keith Thompson <kst-u@mib.org>: May 23 08:21PM -0700

> On 24/05/2019 00:29, Keith Thompson wrote:
[...]
>> a lower level than most non-assembly languages. But as I see it, the
>> biggest gap is between assembly languages, where each program specifies
>> a sequence of instructions for a particular CPU,
 
You snipped the following two lines, which are very relevant to the
point I was making:
 
>> and non-assembly
>> languages (including C), where each program specifies run-time behavior.
 
(I meant to write "(including C and C++)".)
 
 
> mov dword [R],1234.0
> mov dword [R],1234
 
> is undefined behaviour.
 
The point you seem to be missing is that an HLL (such as C or C++)
says *nothing* about that sequence of ASM, or about any other
sequence of ASM. An HLL concerns itself with the behavior of code
written in that HLL.
 
Perhaps you could restate your objections in terms of C++ source
code and run-time behavior rather than trying to bring assembly
language into it.
 
[...]
 
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
David Brown <david.brown@hesbynett.no>: May 24 10:04AM +0200

On 24/05/2019 02:45, Bart wrote:
>> a lower level than most non-assembly languages.  But as I see it, the
>> biggest gap is between assembly languages, where each program specifies
>> a sequence of instructions for a particular CPU,
 
[ Restoring the missing part, with later corrections ]
>> and non-assembly languages (including C and C++), where each program
>> specifies run-time behavior.
 
(Pretty much everything I write in this post applies equally to C and
C++ - I'm going to write "C" for convenience and laziness.)
 
I'd agree that this is the biggest gap. I would not say it is the
/only/ difference, but it is certainly the biggest.
 
Another key difference relevant here is that with assembly, you
specifically say exactly which loads and stores you do, and they are
carried out as written. In C, you do not - there are lots of
restrictions on the accesses you can legally do. (I am using the term
"legally" to cover all aspects such as syntax, constraints, and defined
behaviour.) And even when an access is allowed, there is no requirement
for the compiler to generate directly corresponding instructions - it
can generate anything it likes that has the same observable behaviour.
In particular, stores can be merged, loads can be cached in registers,
unused results can be omitted entirely, accesses can be re-ordered,
local variables can be omitted, etc.
 
> It's not really about specific instructions, which are not of great
> interest, but being to specify what you want in more detail and without
> interference.
 
In C, you specify what you want in a good deal more detail than higher
level languages - but not as much detail as in assembly. You specify it
using the C language to describe the effect on the C abstract machine -
unlike assembly, which specifies it at the level of the target ISA.
 
>       mov dword [R],1234
 
> is undefined behaviour. I don't think C is at a high enough level or
> smart enough to decide that for me.
 
C /is/ at a level where it /does/ decide that. This is a point of C
that most programmers like - they don't need to fiddle around with small
details of how accesses are done, or how they could be more efficient.
 
I have worked with C compilers that don't do any optimisation or
re-arrangement of loads and stores - they are a real PITA to use
sensibly, and efficiently, the source code is a mess of "cache"
variables, and it is all very target dependent as you need to figure out
what should go in registers. It is barely a step up from assembly.
 
If you decide you need a language that gives you this kind of detailed
control of accesses (and the pain this entails), then C is not the
language for you. But what you /must/ understand here is that this is
not C's fault! It is not the C language or compilers that have the
problem - it is you that wants something that C cannot give you. And
you must also understand that what you want here is unusual. It is not
the kind of detailed control many programmers want - even those dealing
with extremely low-level coding situations.
 
And one thing I have been missing in your discussions about C is the use
of "volatile". It is true that up to C17, the C standards have been a
bit vague on the details of volatile - in particular, they discuss
"access to volatile objects". With C17, this changes to "volatile
accesses" - putting it in line with the way /all/ C compilers implement
volatile. If you want to make an access exactly as specified,
disregarding many of the rules of C (but not the syntax rules,
obviously), then make the access volatile. This tells the compiler that
you know something odd might be happening beyond its ken, so it should
do exactly what you write here. If you want to muck around with
accesses via incompatible types and that kind of thing, you'll need
"volatile" on the stores and on later reads, but you can write that if
you want.
 
> You need to be able to do some
> underhand things with this kind of language without /having/ to use ASM,
> and without having to tie yourself up in knots getting around the language.
 
/You/ might need to do this sort of thing - I don't think many other
people do. I am quite happy working with the language and tools, rather
than fighting against them. On the very rare occasions when I might
need to do something odd, then it's okay to use "volatile", or unions,
or memcpy - rare code doesn't have to be as simple as common code. And
of course, such weird code can be tidied away in a function, or if
necessary for efficiency, an inline function or macro. It does not
impede on the clarity of the main code logic.
 
>      call addstring        ; this is C++ after all
 
> and leave the bigger decisions to the programmer, who will be using this
> kind of language for a reason.
 
No, C should not stick to that. If you want a language that sticks to
such limited features, C is not the right choice. Such a limited
language would be of very little use to anyone. C is popular because it
is a higher level language giving more flexibility, power and efficiency
than such a limited language would do - while also eliminating the need
of such a language in almost all cases.
David Brown <david.brown@hesbynett.no>: May 24 10:14AM +0200

On 24/05/2019 00:35, Keith Thompson wrote:
 
> Yes.
 
> (You're citing the C standard. I believe C++ has similar rules, but I
> find the C standard easier to navigate.)
 
That's my opinion too. It is at least partly due to familiarity, but
also the C standard is shorter, the language simpler, and the standards
change less (it's often enough to say "the C standard" without giving
the version, as numbering is quite consistent from C99 onwards).
However, I should have made it clear that it was the C standard I
referred to.
 
> It's not necessary to make byte pointers bigger than word pointers
> because there are enough unused bits to store the offset internally.
> (This is/was all handled in generated code by the compiler.)
 
Yes. I hadn't really thought about this possibility until this thread.
 
I have worked with a DSP with 16-bit accesses. It would have been very
nice if it had support for a different type of pointer that could access
8-bit chars, even though such accesses would be slower than for 16-bit
and bigger types. It would not have needed a bigger type for its char
or void pointers, since the device in question did not have a very large
data address range. It would just have needed a slightly different
encoding for the address.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: May 24 10:36AM +0100

On Fri, 24 May 2019 10:04:10 +0200
David Brown <david.brown@hesbynett.no> wrote:
[snip]
> accesses via incompatible types and that kind of thing, you'll need
> "volatile" on the stores and on later reads, but you can write that if
> you want.
 
When your refer to "accesses via incompatible types", are you saying
that in C17 'volatile' overrides C's aliasing rules? I suppose we
should be used to keyword overloading, but that one looks a bit odd.
 
If so, how does that work? Is it applied to function arguments (like a
kind of 'anti-restrict' keyword) - it couldn't be applied effectively
to the cast itself as, in the example under discussion, it is the
compiler's optimization of the 'foo' function in reliance on aliasing
rules which is the proximate trigger for the problem, and foo's
transformation to object code cannot depend on factors outside the
visibility of 'foo'. If it is applied to function arguments, it
wouldn't help with the example under discussion because 'foo' is fine
in its own terms. It is how it is "driven" which is the issue - it's
float* argument should have been driven via a union variable or a float
variable.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: May 24 10:42AM +0100

On Fri, 24 May 2019 10:36:05 +0100
> in its own terms. It is how it is "driven" which is the issue - it's
> float* argument should have been driven via a union variable or a float
> variable.
 
By the way I didn't actually know there was a C17 (I don't follow C
particularly closely). Hence my question.
blt_69xomnp@s9r2i6c24y0ft__c6.gov: May 24 09:51AM

On Thu, 23 May 2019 21:21:52 +0200
>not mean C is not a high level language, especially because there /is/
>an abstraction between the cpu and code. It is specifically designed to
>be a minimal abstraction on many systems, but it is still there.
 
There is an abstraction but its not a logical one, its an instruction model
one. C++ does have some logical abstraction but C IMHO does not.
blt_fu@rdaz8fb8rhixil8x.ac.uk: May 24 09:52AM

On Thu, 23 May 2019 16:29:56 -0700
>implement the specified run-time behavior. There needn't even be
>an ADD instruction; a compiler could simply generate code to store
>30 in c, or omit it altogether if the value is never used.
 
Optimisation silliness should be ignored in this argument since optimising
assemblers can be quite happy to rearrange or delete instructions too.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: May 24 11:23AM +0100

On Fri, 24 May 2019 09:51:07 +0000 (UTC)
> On Thu, 23 May 2019 21:21:52 +0200
> David Brown <david.brown@hesbynett.no> wrote:
[snip]
> >be a minimal abstraction on many systems, but it is still there.
 
> There is an abstraction but its not a logical one, its an instruction model
> one. C++ does have some logical abstraction but C IMHO does not.
 
Herein lies your problem. Your opinion about C is wrong. C is not a
glorified macro assembler, but writes to a specification for an abstract
machine, and is subject to an observable behaviour requirement for
conforming code on that machine. You are plainly using the wrong
language for your purposes, based on this misapprehension of yours.
(In any event, we were discussing an example written in C++.)
 
Why do you keep flogging this dead horse? You have been alerted to the
parts of the C and C++ standards which say that the code in question
gives rise to undefined behaviour which imposes no requirement for
observable behaviour. You have had explained to you that in C and C++
compilers are permitted to carry out optimizations including type-based
alias optimization provided they meet observable behaviour
requirements. You have had this demonstrated to you with an example
which emitted code which was for you "wrong" with optimizations
enabled. You have had an explanation about why the compiler probably
emitted this code. Pig headed you may be, but surely even you can't
really believe as you claim that this is a compiler bug (such a bug
occurring simultaneously in both gcc and clang and going even now
undetected and uncorrected is completely implausible even if it is
accepted that you don't understand the C and C++ standards).
 
The fact that for you optimization is "a trial and error process" is a
further indicaation you must be writing significant amounts code with
undefined behaviour based on your misunderstanding about C. I have
never ever found optimization to be a matter of trial and error,
except in the performance sense.
 
And yet you go on an on, arguing a point which even you must by now
realise is fatuous. What's the point?
blt__6qv0@o2s9b3.edu: May 24 10:50AM

On Fri, 24 May 2019 11:23:13 +0100
 
>Herein lies your problem. Your opinion about C is wrong. C is not a
>glorified macro assembler, but writes to a specification for an abstract
>machine, and is subject to an observable behaviour requirement for
 
x86 assembler is a spec for an abstract machine given that its been a long
time since most of those instructions were executed as is on the silicon so
what is your point? There is a clear mapping from a C instruction to 1 or
more assembly instructions.
 
>gives rise to undefined behaviour which imposes no requirement for
 
Undefined behaviour is for something like 2 / 3. When the types are specifically
given in the program and the operations simply and clear there is no excuse for
behaviour being undefined.
 
>The fact that for you optimization is "a trial and error process" is a
>further indicaation you must be writing significant amounts code with
 
No, its an indication that I've written my own and debugged others code enough
to know that optimisers can get it wrong, quite badly in some circumstances.
 
>And yet you go on an on, arguing a point which even you must by now
>realise is fatuous. What's the point?
 
Its usenet.
Bart <bc@freeuk.com>: May 24 12:35PM +0100

On 24/05/2019 09:04, David Brown wrote:
 
>> is undefined behaviour. I don't think C is at a high enough level or
>> smart enough to decide that for me.
 
> C /is/ at a level where it /does/ decide that.
 
Obviously, I don't agree. The programmer decides whether this kind of
type-punning makes sense or not, not the language. He/she can do so
because they know something about the program that the compiler doesn't.
 
The language should still be low enough level, when working with
primitive types, that they can do this. You can't at a much higher level
because the actual data is hidden behind extra pointers and data
structures and unknown representations.
 
This is why someone chooses to work in a somewhat painful-to-write
language (but which is not as excruciating as ASM).
 
This is a point of C
> sensibly, and efficiently, the source code is a mess of "cache"
> variables, and it is all very target dependent as you need to figure out
> what should go in registers. It is barely a step up from assembly.
 
You work mostly with small devices. I work with PCs, which have plenty
of processing power; it's mainly bloated, badly written software that
can make it exasperatingly slow, despite the best efforts of the
compiler optimisers.
 
But even the worst C compiler will produce code that is faster than any
language that works by interpreting byte-code.
 
 
> If you decide you need a language that gives you this kind of detailed
> control of accesses (and the pain this entails),
 
No, the language should just keep out of the way. It should implement
what the code says, and do just enough optimisations as are reasonable.
 
What compilers such as gcc are doing becomes unreasonable when the
behaviour of a program changes dramatically. And then they put the blame
on the programmer! (See examples I posted two days ago in 'C/C++ as a
target lanuage' fork.)
 
then C is not the
> language for you.
 
Yes I know. That's why I've had to maintain my own (out of protest
really since I don't have any real work to apply them too).
 
But what you /must/ understand here is that this is
> with extremely low-level coding situations.
 
> And one thing I have been missing in your discussions about C is the use
> of "volatile".
 
I think all my compilers implement 'volatile', without even being aware
of it!
 
>> and without having to tie yourself up in knots getting around the language.
 
> /You/ might need to do this sort of thing - I don't think many other
> people do.
 
I don't think what I do is that unusual. Take this example (although
normally dynamically allocated):
 
int64_t A[1000];
 
A is an int array, but one the programmer knows contains a fixed-up
byte-code sequence (ie. one ready-to-run in memory, so some things are
converted to pointers).
 
For that purpose, it may be necessary for any element of A to be
interpreted as one of:
 
* A pointer to a function that will execute this particular
byte-code op (there may be 0 or N operands following)
 
* An int64 operand
 
* A float64 operand
 
* A pointer to a string
 
* Either the lower or upper half of an int128 operand split across
two elements
 
* A Bool operand
 
* A uint64 operand
 
* A pointer to a variable of the byte-code's host language
 
* A pointer to a big-number value
 
* A label represented as pointer to an element of A[]
 
You get the idea. Sometimes also you will be executing this code (so an
int containing a float64 is accessed as such), and sometimes other
manipulations will be done that that int is just accessed as an int.
 
There might be all sorts of worthy ways of representing while this
working within C's rules, but an int array (of an int type the
programmer has chosen to be big enough) is the simplest.
 
However, when the original code for this program is not written in C,
and simply uses an int-array like the above, then all those worthy
methods need to somehow be automatically introduced if any
source-to-source translator wants to turn it into correct C.
 
That's not going to happen.
 
(I've done such a translation, maintaining the simple int array in the
C, and it worked fine. But there may or may not be UB lurking somewhere,
if so then it's an issue with C, since there's nothing wrong with how
the original works, and I'm not going to pander to such a language.)
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: May 24 12:41PM +0100

On Fri, 24 May 2019 10:50:27 +0000 (UTC)
> time since most of those instructions were executed as is on the silicon so
> what is your point? There is a clear mapping from a C instruction to 1 or
> more assembly instructions.
 
No, there is no clear mapping from a C or C++ "instruction" to 1 or
more assembly instructions. If there were, C and C++ would be glorified
macro assemblers and there would be no need for an abstract machine.
There would be an actual machine, such as your x86.
 
(As it happens, C and C++ don't have "instructions", they have amongst
other things operators, statements and expressions.)
 
 
> Undefined behaviour is for something like 2 / 3. When the types are specifically
> given in the program and the operations simply and clear there is no excuse for
> behaviour being undefined.
 
Undefined is undefined, compilers will act on it and the consequences
have been demonstrated to you empirically as well as by reference to
the standards. Whether or not you think it is right to be undefined is
beside the point. It is undefined and compilers will produce code which
doesn't do what you think it should because of that, as has been
demonstrated.
 
> >further indicaation you must be writing significant amounts code with
 
> No, its an indication that I've written my own and debugged others code enough
> to know that optimisers can get it wrong, quite badly in some circumstances.
 
No, given what you say above it's definitely an indication that your
code is inadequate. Your explanation that the example you have been
shown represents a compiler bug rather than a bug in your understanding
is, as I have mentioned previously, implausible.
 
> >And yet you go on an on, arguing a point which even you must by now
> >realise is fatuous. What's the point?
 
> Its usenet.
 
This is usenet, but it doesn't explain your behaviour. I doubt it is
just trolling.
 
Possibly you feel an urge not to appear as a dick and don't know how to
climb out of the hole you have dug, but the more you carry on with your
repetitive and incorrect assertions in the face of all the evidence,
and of advice from others, the less that is likely to succeed. Possibly
it is just that you have some impediment which makes it impossible for
you to distinguish between (i) what C and C++ are, and (ii) what you
think C and C++ should be. If so, it is a shame that it affects your
C++ coding abilities in the way you indicate.
Ian Collins <ian-news@hotmail.com>: May 25 12:04AM +1200

On 24/05/2019 23:41, Chris Vine wrote:
 
>> Its usenet.
 
> This is usenet, but it doesn't explain your behaviour. I doubt it is
> just trolling.
 
While you are usually spot on, in this case I think you have been trolled...
 
--
Ian.
David Brown <david.brown@hesbynett.no>: May 24 02:09PM +0200


> x86 assembler is a spec for an abstract machine given that its been a long
> time since most of those instructions were executed as is on the silicon so
> what is your point?
 
x86 assembler is a spec for the x86 ISA. Yes, it is abstract in that
the underlying hardware is physically different. But so what? What
possible bearing does that have on C or C++ ?
 
> There is a clear mapping from a C instruction to 1 or
> more assembly instructions.
 
No there is not.
 
Many of the operations in C were originally picked with a view to
compilers being able to simply and efficiently generate code on certain
cpus of that time. An aim of C was that you would not have to use
assembly much - that necessitated compilers being able to generate
efficient code. That is about the most you can say about mappings from
C to assembly. (This has not changed with C++.)
 
 
>> gives rise to undefined behaviour which imposes no requirement for
 
> Undefined behaviour is for something like 2 / 3.
 
What an odd example to pick, given that its behaviour is fully defined
in all programming languages I have seen.
 
> When the types are specifically
> given in the program and the operations simply and clear there is no excuse for
> behaviour being undefined.
 
As long as the values are appropriate for the operation, then there will
be no undefined behaviour. If you use inappropriate values, the
behaviour is undefined. This is nothing more than "garbage in, garbage
out". It never ceases to amaze me how some people can claim to be
programmers and still have trouble with the concept of undefined
behaviour - it is so fundamental to /all/ programming in /all/
languages. Provide valid inputs, and you can expect the requested
behaviour - provide invalid inputs, and you cannot expect anything about
the behaviour or results.
 
Perhaps what you are trying to say is that you'd prefer certain common
operations in C to be defined for all inputs. That is, of course,
impossible in general - but it /could/ be done for some operations. And
some compilers /do/ have defined behaviour for some things that are
undefined in C. Others don't, and with good reason.
 
 
>> further indicaation you must be writing significant amounts code with
 
> No, its an indication that I've written my own and debugged others code enough
> to know that optimisers can get it wrong, quite badly in some circumstances.
 
I have come across a few compiler bugs in my time. But the kind of
things we are discussing here are not bugs, and the optimiser has not
got anything wrong. The /programmer/ has got things wrong - that is
vastly more common in my experience.
 
David Brown <david.brown@hesbynett.no>: May 24 02:27PM +0200

On 24/05/2019 11:36, Chris Vine wrote:
 
> When your refer to "accesses via incompatible types", are you saying
> that in C17 'volatile' overrides C's aliasing rules? I suppose we
> should be used to keyword overloading, but that one looks a bit odd.
 
I am not actually sure if the C17 /requires/ that volatile accesses
override the aliasing rules like this. But I believe all known
compilers behave as it they do - and have done since before C17's
improvements to the description of volatile. Basically, if you write
"*p = x;" where "p" is a pointer to volatile, then it will be done -
even if the compiler knows the types are wrong, or the store is
redundant, or the alignment is bad, or the pointer is out of bounds.
Similarly for reads of volatiles.
 
Look back at the test code we had (in a version that works for C and
C++, does not I/O, and uses separate functions - making it simple to
view with gotbolt.org assembly generation):
 
int foo( float *f, int *i ) {
*i = 1;
*f = 0.f;
 
return *i;
}
 
int bar(void) {
int x = 0;
 
x = foo((float*) &x, &x);
return x;
}
 
gcc, with -O2, correctly and efficiently compiles bar to:
 
bar():
mov eax, 1
ret
 
No floats are stored anywhere, and the integer store can be eliminated.
 
If we change the parameters of "foo" to "volatile float * f, int * i",
we get:
 
bar():
mov DWORD PTR [rsp-4], 0x00000000
mov eax, 1
ret
 
Now the compiler has to make the float store, even though the value is
never accessed in any other way - the store alone does not affect the
/read/ of the integer variable.
 
Making the parameters "volatile float * f, volatile int * i" gives:
 
bar():
mov DWORD PTR [rsp-4], 1
mov DWORD PTR [rsp-4], 0x00000000
mov eax, DWORD PTR [rsp-4]
ret
 
The compiler has to make both stores, and the read.
 
 
I am not convinced that even C17 enforces this behaviour, but I am
convinced that compilers implement it this way.
 
 
> in its own terms. It is how it is "driven" which is the issue - it's
> float* argument should have been driven via a union variable or a float
> variable.
 
I am not sure if I have answered your question as such, but I hope I
managed to help a little.
David Brown <david.brown@hesbynett.no>: May 24 02:33PM +0200

On 24/05/2019 11:42, Chris Vine wrote:
 
 
> By the way I didn't actually know there was a C17 (I don't follow C
> particularly closely). Hence my question.
 
C17 is mostly a "bug fix" of C11 (and with nicer typography, IMHO, if
that kind of thing interest you). One noticeable difference is that C11
and prior discuss "access to volatile objects", how they should be
evaluated, and how they are considered "observable behaviour" for
execution. In C17, this is replaced by "volatile accesses". Prior to
C17, if you have:
 
int i;
 
*(volatile int *) &i = 1;
 
it is not clear if this is observable behaviour or if the compiler has
to handle it specially. However, in a committee meeting long ago
(according to what I have read somewhere - no references) all compiler
writers agreed that it was so obviously a volatile access that there was
no need to bother changing the wording of the standard. Their users
would have rebelled long ago if such casts were not handled in the same
way as "accessing a volatile object".
 
C17 simply documents the existing de facto standard behaviour here.
James Kuyper <jameskuyper@alumni.caltech.edu>: May 24 08:41AM -0400

> On Thu, 23 May 2019 21:21:52 +0200
...
>> be a minimal abstraction on many systems, but it is still there.
 
> There is an abstraction but its not a logical one, its an instruction model
> one. C++ does have some logical abstraction but C IMHO does not.
 
Are you aware of what precisely the C standard says about this?
 
"The semantic descriptions in this International Standard describe the
behavior of an abstract machine in which issues of optimization are
irrelevant." (5.1.2.3p1)
 
"In the abstract machine, all expressions are evaluated as specified by
the semantics. An actual implementation need not evaluate part of an
expression if it can deduce that its value is not used and that no
needed side effects are produced (including any caused by calling a
function or accessing a volatile object)." (5.1.2.3p4)
 
"The least requirements on a conforming implementation are:
— Accesses to volatile objects are evaluated strictly according to the
rules of the abstract
machine.
— At program termination, all data written into files shall be identical
to the result that execution of the program according to the abstract
semantics would have produced.
— The input and output dynamics of interactive devices shall take place
as specified in. The intent of these requirements is that unbuffered or
line-buffered output appear as soon as possible, to ensure that
prompting messages actually appear prior to a program waiting for input.
This is the observable behavior of the program." (5.1.2.3p6)
 
Understand that "least requirements" means that as long as these
requirements are met, it doesn't matter if other things the standard
says aren't actually obeyed - as long as the observable behavior is the
same if those things were obeyed.
scott@slp53.sl.home (Scott Lurndal): May 24 12:58PM

>implement the specified run-time behavior. There needn't even be
>an ADD instruction; a compiler could simply generate code to store
>30 in c, or omit it altogether if the value is never used.
 
Compilers are also able to take advantage of a particular processor
microarchitecture to generate more efficient code (i.e. interleave
instructions in such a way as to keep both ALUs busy in the processor
pipeline). So, you can build optimized binaries for many different
processors (e.g. using gcc's -mtune=cpu-type option) without changes to
the source code.
David Brown <david.brown@hesbynett.no>: May 24 04:12PM +0200

On 24/05/2019 13:35, Bart wrote:
>>> smart enough to decide that for me.
 
>> C /is/ at a level where it /does/ decide that.
 
> Obviously, I don't agree.
 
Please /stop/ writing such things. Make it clear if you mean:
 
a) "I don't agree that C is at this level, because I refuse to look at
the standards defining the language, and I would rather poke my eyes out
with a sharp stick than accept such indisputable facts"
 
or
 
b) "I think C should have been designed differently, and consider C to
be a terrible language because it was not designed the way /I/ want it
to have been designed"
 
 
If you had meant to write "I would have preferred C to be different
here, then it would have suited my needs better", then you should have
written that.
 
 
 
> The programmer decides whether this kind of
> type-punning makes sense or not, not the language.
 
The programmer /did/ decide - when he/she decided to use C rather than a
different language, or a C variant such as "gcc -fno-strict-aliasing".
 
> He/she can do so
> because they know something about the program that the compiler doesn't.
 
If the programmer is unable to tell the compiler about this (by one of
several means), then they are not capable of writing the code in the C
language.
 
> structures and unknown representations.
 
> This is why someone chooses to work in a somewhat painful-to-write
> language (but which is not as excruciating as ASM).
 
Very few C programmers, I think, consider it a "painful to write" language.
 
> compiler optimisers.
 
> But even the worst C compiler will produce code that is faster than any
> language that works by interpreting byte-code.
 
There are many reasons code can be slow - I think we can agree on that
without trying to figure out details.
 
One interesting thing about PC programming these days is that modern x86
processors are very forgiving about badly generated and badly optimised
code. Often it doesn't matter if there are several times more
instructions than are needed, because it is memory access that is the
bottleneck anyway.
 
For other kinds of programming - or more careful PC programming -
quality optimisation makes a big difference.
 
>> control of accesses (and the pain this entails),
 
> No, the language should just keep out of the way. It should implement
> what the code says, and do just enough optimisations as are reasonable.
 
And who defines what optimisations are "reasonable" ? For C, these are
clearly defined - anything that does not affect the observable behaviour
of valid code with defined behaviour is "reasonable". Vague hand-waving
and claims that this is "obvious" simply don't cut it.
 
 
> What compilers such as gcc are doing becomes unreasonable when the
> behaviour of a program changes dramatically.
 
Optimisations don't affect the behaviour of correct programs (except for
their speed and size, of course). If the behaviour of the program (with
identical inputs, obviously) changes due to optimisation, then the code
was incorrect. It's that simple.
 
 
> And then they put the blame
> on the programmer! (See examples I posted two days ago in 'C/C++ as a
> target lanuage' fork.)
 
Yes - the programmer is to blame.
 
Compilers can always do a better job at helping programmers find their
mistakes, of course.
 
I read the examples you posted there, and gave a detailed feedback and
suggestions. As usual, you basically ignored any helpful advice as you
prefer whining to solving your issues.
 
 
 
>> language for you.
 
> Yes I know. That's why I've had to maintain my own (out of protest
> really since I don't have any real work to apply them too).
 
Your sensible choices here seem to be either to go away and work on your
own little private language that solves problems no one else has, or to
accept C for what it is, and learn to use it correctly. Vocally hating
C (and C++) while misunderstanding it and failing to use the solutions
it gives, does not seem very productive behaviour.
 
>> of "volatile".
 
> I think all my compilers implement 'volatile', without even being aware
> of it!
 
I hope by that you mean your compilers treat all data as though it were
volatile. That is perfectly allowed by C (indeed, it is an example
given in 5.1.2.3p9 of the C11 standard). It is not going to be very
efficient - as I said, I've worked with C tools like that and they are
far more effort than a decent compiler.
 
 
> A is an int array, but one the programmer knows contains a fixed-up
> byte-code sequence (ie. one ready-to-run in memory, so some things are
> converted to pointers).
 
Right - that is an unusual and specialised case. Very, very few
programmers get involved in the details of any kind of byte code.
 
 
>   * A pointer to a big-number value
 
>   * A label represented as pointer to an element of A[]
 
> You get the idea.
 
Yes. Use a union. Problem solved.
 
> C, and it worked fine. But there may or may not be UB lurking somewhere,
> if so then it's an issue with C, since there's nothing wrong with how
> the original works, and I'm not going to pander to such a language.)
 
You make such mountains from molehills because you fixate on the wrong
ideas from day one.
Daniel <danielaparker@gmail.com>: May 23 07:18PM -0700

On Thursday, May 23, 2019 at 2:39:51 PM UTC-4, Rick C. Hodgin wrote:
 
> You are so wicked, Daniel.
 
:-)
 
"Judge not, that ye be not judged"
 
— Matthew 7:1-3
 
"And why beholdest thou the mote that is in thy brother's eye, but considerest not the beam that is in thine own eye?"
 
— Matthew 7:3-5
 
"whosoever shall say, Thou fool, shall be in danger of hell fire."
 
— Matthew 5:22
queequeg@trust.no1 (Queequeg): May 24 02:32AM


> And Satan invented fossils, yes?
 
Leigh,
 
Did you really have to quote all his BS just to add one line?
 
--
https://www.youtube.com/watch?v=9lSzL1DqQn0
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: May 23 08:29PM -0700

On Thursday, May 23, 2019 at 10:19:11 PM UTC-4, Daniel wrote:
> — Matthew 7:1-3
 
> "And why beholdest thou the mote that is in thy brother's eye, but considerest not the beam that is in thine own eye?"
> — Matthew 7:3-5
 
That's only Matthew 7:3.
 
Do you know what those verses teach? They teach do not judge
if you are doing the things you're judging others for doing, or
if you are doing things you shouldn't be doing. If you keep read-
ing in Matthew 7, you'll find this verse:
 
5 Thou hypocrite, FIRST cast out the beam out of thine own
eye; AND THEN shalt thou see clearly to cast out the mote
out of thy brother's eye.
 
The teaching is to take care to be serving God rightly first,
and then open your mouth to teach.
 
John also teaches:
 
https://www.biblegateway.com/passage/?search=John+7:24&version=NIV;KJV
 
24 Judge not according to the appearance, but judge righteous
judgment.
 
The purpose in studying the Bible is to learn the truth. The
purpose in twisting verses to suit what you want it to is to
deceive others.
 
God calls us to go forth into this world and teach people the
truth, to undo the work of the devil and his false teaching re-
garding the things of God. There are enough deceivers out there,
Daniel. What God calls us to be is truth teachings, and to be
sincere, righteous, honest, non-deceiving, and to do so purpose-
fully for His glory and His Kingdom.
 
> "whosoever shall say, Thou fool, shall be in danger of hell fire."
> — Matthew 5:22
 
That's only part of Matthew 5:22.
 
https://biblehub.com/text/matthew/5-22.htm
 
22 But I say unto you, That whosoever is angry with his brother
WITHOUT A CAUSE shall be in danger of the judgment: and who-
soever shall say to his brother, raca, shall be in danger of
the council: but whosoever shall say, Thou fool, shall be in
danger of hell fire.
 
I do not call you a fool. The things you are teaching here are
wicked. You are using the Bible to justify the position or argu-
ment that I am in some way teaching something false. You are mis-
characterizing God, and the scripture, in so doing.
 
What does the Bible teach about those who twist scripture, result-
ing in other people being harmed by its manipulation (causing them
to stumble)?
 
https://www.biblegateway.com/passage/?search=Luke+17%3A1-2&version=NIV;KJV
 
1 Jesus said to his disciples: "Things that cause people to
stumble are bound to come, but WOE TO ANYONE THROUGH WHOM
THEY COME.
2 It would be better for them to be thrown into the sea with
a millstone tied around their neck than to cause one of
these little ones to stumble.
 
Your teachings are causing those who would hear the teachings of
the Bible to stumble. The assessment I made of you and your
posts is accurate. Jesus said we would know them by their fruit:
 
https://www.biblegateway.com/passage/?search=matthew+7%3A16-20&version=NIV;KJV
 
==> 16 Ye shall know them by their fruits. Do men gather grapes
of thorns, or figs of thistles?
17 Even so every good tree bringeth forth good fruit; but a
corrupt tree bringeth forth evil fruit.
18 A good tree cannot bring forth evil fruit, neither can a
corrupt tree bring forth good fruit.
19 Every tree that bringeth not forth good fruit is hewn down,
and cast into the fire.
==> 20 Wherefore by their fruits ye shall know them.
 
Your fruit bears out under scrutiny, Daniel, hence my posting you
were wicked. You are misrepresenting God, and doing so to cast
the true teachings of God into something negative, setting good
for evil, and evil for good. Unless you repent, it will literally
be to your soul's destruction. And that's not a threat from me,
but a warning from God found throughout scripture.
 
--
Rick C. Hodgin
Daniel <danielaparker@gmail.com>: May 24 07:10AM -0700

On Thursday, May 23, 2019 at 11:29:40 PM UTC-4, Rick C. Hodgin wrote:
 
> You ... cast the true teachings of God into something negative
 
Well, there are some things negative in the texts. Why was it necessary when
taking Jerico to kill every man, woman, baby, ox, sheep and donkey? For what
reason do we need to kill women who cannot prove that they were virgins on
their wedding night? Or give the death penalty to the virgin if she does not
cry out for help when raped? Or put to death gays and lesbians? Why is it
permitted for a man to sell his daughter as a slave, and why cannot she be
freed as male slaves were after seven years?
 
And herein is your problem, when you read the texts, you assume everything
in them is good, in some sense, and hence all of the things above permit
themselves of a positive spin. I think you should go back and reread many of the later texts and see them as a movement _away_ from the ancient law that
was expressed in the earlier ones. And you should also learn more. Thomas
Jefferson knew about the fable of the generation of Minerva in the brain of
Jupiter, and much else, but you don't seem to know _anything_ about the
wider context in which the great religions evolved.
 
Best regards,
Daniel
Paavo Helde <myfirstname@osa.pri.ee>: May 24 02:31PM +0300

How to make offsetof() usage legal in this example? Is there a better
way instead of using offsetof? Basically I want to restore a full object
pointer from a pointer to a member object. This example comes from some
heavily space-optimized code, so adding any new helper data members
anywhere is out of question.
 
The code probably works fine with all compilers/platforms it will ever
see, but the compiler spits out nasty warnings, because there is some
data both in the base and derived classes, making the class not
"standard layout".
 
#include <cassert>
#include <cstddef>
 
class Base {
int x;
public:
Base(): x(0) {}
};
 
class Inner {
int y;
public:
Inner(): y(0) {}
};
 
class Derived : public Base {
Inner inner;
public:
Inner* GetInner() {
return &inner;
}
static Derived* OwnerOf(Inner* inner);
};
 
Derived* Derived::OwnerOf(Inner* inner) {
return reinterpret_cast<Derived*>(
reinterpret_cast<char*>(inner) - offsetof(Derived, inner));
}
 
int main() {
Derived a;
Inner* p = a.GetInner();
Derived* q = Derived::OwnerOf(p);
assert(q == &a);
}
 
> g++ -Wall test1.cpp -std=c++17
In file included from /usr/include/sys/_types.h:159:0,
from /usr/include/sys/reent.h:15,
from /usr/include/stdlib.h:18,
from
/usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/cstdlib:75,
from test1.cpp:3:
test1.cpp: In static member function 'static Derived*
Derived::OwnerOf(Inner*)':
test1.cpp:27:79: warning: offsetof within non-standard-layout type
'Derived' is undefined [-Winvalid-offsetof]
return reinterpret_cast<Derived*>( reinterpret_cast<char*>(inner) -
offsetof(Derived, inner));
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: