- std::hexfloat - 20 Updates
- [Jesus Loves You] How'd we become so depraved? - 4 Updates
- offsetof - 1 Update
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:
Post a Comment