Friday, August 23, 2019

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

"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Aug 23 07:22AM +0200

On 23.08.2019 00:45, Ben Bacarisse wrote:
>> And I don't think you think you're smarter than everybody else in this
>> group just for holding an opinion on UB that nobody else here shares.
 
> Why do you think no one else shares Tim's opinion?
 
Because he's been arguing his view for a very long time and nobody's
supported him.
 
Also because it's a totally impractical view so I'd not expect any
practitioner to support it.
 
 
> Tim has not said anything here about UB that I disagree with.
 
Well then, speak up in defense of his view.
 
 
> You have, but I've found
> my life to be more pleasant if I don't reply to your posts, and anyway,
> Tim has it covered.
 
If I have said things that you disagree with about UB, then most likely
so have everybody else who's responded to Tim on this subject. As far as
I recall you didn't speak up at any point, so your explanation, that
you're afraid of replying to /me/, just doesn't hold water.
 
So, your explanation for keeping silent appears to be an untruth that
you know is an untruth, anyway embedded in an ad hominem attack.
 
The thread has been civilized so far, but now (1) Tim has added a social
silly-argument (that to disagree with him one must think of oneself as
smarter than all people on the committee), and (2) you add an untruth
and an ad hominem attack.
 
That development of dishonest more social argumentation is probably
about something else than that you now suddenly feel you're losing a
technical debate.
 
Because you lost this debate very long ago: roughly nobody agree with
you that exceeding resource limits isn't UB. The standard says it is.
And that was noted early on, and repeated a gazillion times.
 
 
Cheers!,
 
- Alf
Ben Bacarisse <ben.usenet@bsb.me.uk>: Aug 23 01:12PM +0100


>> Why do you think no one else shares Tim's opinion?
 
> Because he's been arguing his view for a very long time and nobody's
> supported him.
 
That's not a sound basis for making that assumption.
 
> Also because it's a totally impractical view so I'd not expect any
> practitioner to support it.
 
Impractical views can be correct. As it happens, I don't see this view
as an impractical one, but either way it can still be correct.
 
>> Tim has not said anything here about UB that I disagree with.
 
> Well then, speak up in defense of his view.
 
I don't see what I can add. Tim is a far better writer than I am and
has (I my opinion) put the case accurately and clearly. I don't hold
with the modern idea that my opinion matters, just because I have it. I
try to offer my opinion only when I can see some point in doing so.
 
I chipped in here only because I thought it would be useful to know that
silence can't be read as support for either one view or another.
 
> subject. As far as I recall you didn't speak up at any point, so your
> explanation, that you're afraid of replying to /me/, just doesn't hold
> water.
 
Sorry, it was not intended as an explanation for why I did not reply to
other people (and I did not say I was afraid to reply). There is no one
reason that will explain every time I choose more to post.
 
> So, your explanation for keeping silent appears to be an untruth that
> you know is an untruth, anyway embedded in an ad hominem attack.
 
Why the Latin? "ad hominem" brings to mind a logical fallacy, but I am
not making any logical argument at all. My remark was entirely
emotional. Whilst I enjoy reading your posts, I have not enjoyed my
reaction to our direct exchanges. That says as much about me as it does
your posts.
 
> social silly-argument (that to disagree with him one must think of
> oneself as smarter than all people on the committee), and (2) you add
> an untruth and an ad hominem attack.
 
I don't think it's uncivilised to say what I said, and I think it's an
extreme exaggeration to call what I wrote an attack. As I said, it's as
much about my reaction as it about your posting style.
 
> That development of dishonest more social argumentation is probably
> about something else than that you now suddenly feel you're losing a
> technical debate.
 
I am not engaged in a technical debate. I don't recall making any
technical contribution at all.
 
> Because you lost this debate very long ago: roughly nobody agree with
> you that exceeding resource limits isn't UB. The standard says it
> is. And that was noted early on, and repeated a gazillion times.
 
Then your replies make no sense to me. If it is so clearly settled (in
C++, I presume -- maybe C is different here), just cite the unequivocal
text that settles the matter. If anyone disagrees, cite the text
again.
 
--
Ben.
James Kuyper <jameskuyper@alumni.caltech.edu>: Aug 23 09:28AM -0400

On 8/23/19 1:22 AM, Alf P. Steinbach wrote:
 
>> Why do you think no one else shares Tim's opinion?
 
> Because he's been arguing his view for a very long time and nobody's
> supported him.
 
I normally try (and often fail) to avoid paying attention to his posts,
because I've found discussions with him to be unproductive - when I
discuss my disagreements with him, we usually both end up wasting a lot
of time failing to convince each other. He's a lot like you in that regard.
 
He has a strong tendency to elevate what he believes to be the
committee's intent to play a larger role in the interpretation of the
standard than I think appropriate. This can be particularly annoying if
I disagree with him about what that intent was.
If the standard's wording is in conflict with (or even simply fails to
clearly express) the committee's intent, then that wording should be
corrected to clearly express that intent - but that discrepancy doesn't
change the meaning of the words that they actually wrote.
 
However, he is very knowledgeable about the standard, and he is correct
about the pre-eminence of a program's observable behavior. The
standard's definition of "observable behavior" is not "behavior which
can be observed" - it's far more specific than that:
 
"The least requirements on a conforming implementation are:
— Accesses through volatile glvalues are evaluated strictly according to
the rules of the abstract machine.
— At program termination, all data written into files shall be identical
to one of the possible results that
execution of the program according to the abstract semantics would have
produced.
— The input and output dynamics of interactive devices shall take place
in such a fashion that prompting
output is actually delivered before a program waits for input. What
constitutes an interactive device is
implementation-defined.
These collectively are referred to as the observable behavior of the
program. ..." (4.6p7).
 
The term "observable behavior" is in italics, an ISO convention
indicating that this sentence is the official definition of that term.
In the context of the C++ standard, that definition overrides any
alternative interpretation that might otherwise seem appropriate.
 
Note that the amount of stack space taken up by a program does not
qualify as "observable behavior".
 
The standard very explicitly says "The semantic descriptions in this
International Standard define a parameterized nondeterministic abstract
machine. This International Standard places no requirement on the
structure of conforming implementations. In particular, they need not
copy or emulate the structure of the abstract machine. Rather,
conforming implementations are required to emulate (only) the observable
behavior of the abstract machine as explained below." (4.6p1).
 
So if the same observable behavior can be achieved by using either an
iterative or a recursive algorithm, an implementation is free to use
either of those algorithms to achieve it, regardless of which algorithm
you actually expressed in your code. The fact that one algorithm runs a
higher risk of running out of stack space than the other imposes no
requirement on the implementation to avoid that risk (or to embrace it,
for that matter).
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Aug 23 04:02PM +0200

On 23.08.2019 14:12, Ben Bacarisse wrote:
> C++, I presume -- maybe C is different here), just cite the unequivocal
> text that settles the matter. If anyone disagrees, cite the text
> again.
 
That's what's been done, by others and by me.
 
And evidently that's not enough, but I've run out of ideas about what
would help.
 
Anyway, yet again, but for your convenience, first consider C++17 §1.4/2.1:
[quote]
If a program contains no violations of the rules in this International
Standard, a conforming implementation shall, within its resource limits,
accept and correctly execute that program.
[/quote]
 
There are no requirements, here or anywhere else in the standard, about
what should happen or not if the program is not executable within the
implementation's resource limits.
 
There is a requirement, the quoted text, if the the execution is within
the resource limits. There are no requirements otherwise.
 
And "no requirements" is the definition of Undefined Behavior.
 
C++17 §1.3.27
[quote]
1.3.27 [defns.undefined]
undefined behavior
behavior for which this International Standard imposes no requirements
[/quote]
 
One argument that has been made against this very clear and indisputable
(really) wording, is that it doesn't mean that the defined term is
equivalent to the stated definition, but rather that it just implies the
apparent definition. Thus, in that distorted view, UB would imply no
requirements, but no requirements would not necessarily imply UB.
 
A common example of the conventional view, the equivalence of "UB" and
"no requirements", is a `*p` dereferencing of a nullpointer outside of a
`typeid` expression.
 
Everybody (well, almost everybody!) agree that `*p` is Undefined
Behavior because the standard imposes no requirements about it.
 
If the one-way implication view was adopted, dereferencing that
nullpointer would no longer be UB.
 
The same goes for use of the referenced non-object, if any: in the
conventional view it's UB because there are no requirements. With the
one way implication view it's... what? I don't know, it just doesn't
make sense to me.
 
So, that view appears to be entirely silly, impractical, but the
discussion continues, at least for me, i.e. this is my personal reason,
because it's generally a good idea to flesh out what a so long standing
disagreement is about. One can learn things from that. Still I'm as far
as ever from understanding what it's really about.
 
 
Cheers,
 
- Alf
David Brown <david.brown@hesbynett.no>: Aug 23 04:37PM +0200

On 23/08/2019 15:28, James Kuyper wrote:
> higher risk of running out of stack space than the other imposes no
> requirement on the implementation to avoid that risk (or to embrace it,
> for that matter).
 
Since we are expressing opinions - regardless of how much or little they
may be worth - I agree with James here. And as far as I can see, it is
the same as Tim has been saying in this regard.
 
Usually, changing an iterative algorithm into a recursive one will be a
pessimisation, taking more space and run-time. So it is highly unlikely
for a compiler to do this sort of thing - it would quickly become an
unpopular tool. But it is allowed to do so.
 
In the same way, between "int a = b + c;" and "int d = a * 2;", the
compiler is allowed to insert code calculating the first hundred digits
of pi - including the stack space needed for the job. It would be an
unpopular tool, but this would not affect the observable behaviour and
thus it would not affect the conformance of the compiler.
 
The standards do not impose any requirements on quality of
implementation (though they have a few hints here and there) - that is
up to the user.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Aug 23 11:07PM +0200

On 23.08.2019 16:37, David Brown wrote:
> pessimisation, taking more space and run-time. So it is highly unlikely
> for a compiler to do this sort of thing - it would quickly become an
> unpopular tool. But it is allowed to do so.
 
As an example, rewriting a function with loop that uses a fixed size
storage known at compile time, to a recursive function that uses storage
proportional to the function argument, changes the behavior.
 
With the original code one is guaranteed that it will complete.
 
With the recursive one one is not guaranteed completion, because for
large enough values of the parameter it will run out of stack space, an
implementation limit.
 
* * *
 
Essentially the argument about observable behavior is therefore that a
compiler is formally permitted to change a program that guarantees a
result if it compiles and loads, into a program that almost guaranteed
does not produce a correct result.
 
That's a perpetuum mobile construction argument. One doesn't necessarily
know where someone's logic went astray so that they ended up with a
perpetuum mobile design, but the end result is just not reality: it's
absurd. Somewhere in that argument there's necessarily something wrong,
and that's not a QoI issue.
 
 
> In the same way, between "int a = b + c;" and "int d = a * 2;", the
> compiler is allowed to insert code calculating the first hundred digits
> of pi - including the stack space needed for the job.
 
No, that's not the same way.
 
In this example a fixed storage requirement is not changed to a
requirement of storage depending on a parameter.
 
 
> It would be an
> unpopular tool, but this would not affect the observable behaviour and
> thus it would not affect the conformance of the compiler.
 
It would affect observable behavior. One would get wrong results or
crashes. Instead of with a conforming compiler, correct results.
 
 
> The standards do not impose any requirements on quality of
> implementation (though they have a few hints here and there) - that is
> up to the user.
 
That's right, but this isn't QoI, it's about correctness.
 
 
Cheers!,
 
- Alf
Richard Damon <Richard@Damon-Family.org>: Aug 23 07:10PM -0400

On 8/23/19 5:07 PM, Alf P. Steinbach wrote:
 
> That's right, but this isn't QoI, it's about correctness.
 
> Cheers!,
 
> - Alf
 
The Standards unfortunately leave a LOT to QoI.
 
For instance, as far as I know, the compiler would be free to implement
 
unsigned i = 1;
unsigned j = 5;
unsigned k = i + j;
 
as
k = __add_uint(i, j);
 
where __add_uint() was defined as:
 
unsigned __add_uint(unsigned i, unsigned j) {
if(j) return __add_uint(++i, --j);
else return i;
}
 
You might even need something like this (but maybe iterative instead of
recursive) for a processor with very limited arithmetic operations (just
increment/decrement).
 
One such an implementation, the program
 
int main() {
unsigned i = 1U + 65000U;
}
 
might fail due to exhaustion of resources, and that is ok by the
standard. The Standard just requires that there be ONE program that
reaches all of the specified resource limits that the implementation can
process, any other program is allowed to fail for resource limits. This
'one program' rule is one of the big holes in the Standard (at least in
my opinion).
Richard Damon <Richard@Damon-Family.org>: Aug 22 10:58PM -0400

On 8/21/19 2:30 PM, Eli the Bearded wrote:
 
 
> Elijah
> ------
> given MS, probably whatever calender Redmond was on in 1995
 
I thought it was 3 days per 400 years, the multiples of 100 which aren't
multiples of 400 which are the ones the Gregorian Calendar omitted.
Richard Damon <Richard@Damon-Family.org>: Aug 23 02:14PM -0400

UTF-16 takes
2 bytes for values 0-0xFFFF (Unicode Base Plane)
4 bytes for values 0x10000 - 0x10FFFF (All of current Unicode)
 
it CAN'T handle higher code points without some other extension which
would get ugly. That is why Unicode has currently defined that 0x10FFFF
will be the highest code point. I suspect at some point there will be
pressure to change that.
 
UTF-8 takes
1 byte for values 0 - 0x7F (basically ASCII)
2 bytes for values 0x80 - 0xFFF (most western languages)
3 bytes for values 0x1000 - 0xFFFF (Unicode base plane, much of this is
the CJK group)
4 bytes for values 0x10000 - 0x10FFFF, but can actually get to 0x1FFFF
if they extend unicode to higher code points)
 
in the extension (and earlier definition)
5 bytes for values 0x200000 - 0x3FFFFFF
6 bytes for values 0x400000 - 0x7FFFFFFF
 
UTF-16 is more compact only for code that has more characters in the
range 0x1000 - 0xFFFF than in the range 0-0x7F. This MIGHT hold for
Chinese/Japanese/Korean documents that have minimal markup in them. It
largely also requires that CJK document has a lot of 'basic' CJK
characters, as one big reason for extending the Unicode standard past 16
bits was that there were a LOT more characters needed then expected to
handle them.
 
It turns out that UTF-16 was a mistake. It came about because the first
attempts at Unicode thought it could be a 16 bit characters set, and
thus would be UCS-2. It only lives on really because Microsoft decided
to use UCS-2 in windows instead of UTF-8, which admittedly might not
have been a bad decision at the time. When UCS-2 had to become UTF-16 to
handle the full character set, it gets the worse of both sides, it still
is a multi-code character set (but maybe a lot of code can get away with
ignoring it and just not work right with 'esoteric' characters), is less
compact in the most common cases, and has a byte order issue for byte
streams (which most data streams are).
Eli the Bearded <*@eli.users.panix.com>: Aug 23 07:15PM

>> which is around 0.0016 seconds day. That's a big jump in nanoseconds.
> I thought it was 3 days per 400 years, the multiples of 100 which aren't
> multiples of 400 which are the ones the Gregorian Calendar omitted.
 
Hmmm. Yes. This is why I'm happy to use date libraries instead of
writing my own.
 
Elijah
------
there's too much to remember
Ian Collins <ian-news@hotmail.com>: Aug 23 04:17PM +1200

On 23/08/2019 10:09, Tim Rentsch wrote:
> never be public. There are cases where for data members might
> plausibly be made protected rather than private, but never
> public.
 
There is a case where a data member is safe to be public: a const data
member. Access to such a member cannot change a class's invariants.
 
--
Ian.
JiiPee <no@notvalid.com>: Aug 23 07:09AM +0100

On 22/08/2019 23:09, Tim Rentsch wrote:
> that some other people have commented on, and assuming your
> question is meant as generic, with 'age' being merely an
> unfortunate choice of example.)
 
 
correct. the example given might not have been the best. general
question about all situations.
 
 
 
> fred.siblings() += 1; // a new birth in fred's family
 
> To me this pattern reads nicer on the client side than set/get
> functions.
 
 
yes many seems to suggest this online
JiiPee <no@notvalid.com>: Aug 23 07:13AM +0100

On 22/08/2019 23:22, Stefan Ram wrote:
> Instead of asking the object for data and the processing
> to data outside of the object (as when using accessors),
> you should tell the object to do the processing itself.
 
 
sometimes its about storing global settings like:
 
struct Settings
 
{
 
Color backgroundColor;
 
int fontSize;
 
....
 
};
 
 
So I guess this class is not really meant to operate with the values
only return them? it just bundless a group of data.
David Brown <david.brown@hesbynett.no>: Aug 23 09:30AM +0200

On 23/08/2019 08:13, JiiPee wrote:
 
> };
 
> So I guess this class is not really meant to operate with the values
> only return them? it just bundless a group of data.
 
Classes like that still need to have protection. There may not be need
for synchronisation between members for keeping invariants, but usually
you don't want to allow any possibility of other parts of the code
making uncoordinated changes to the values.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Aug 23 11:24AM

On Thu, 2019-08-22, Stefan Ram wrote:
 
> A class needs to protect its invariants.
 
> Therefore, a member can be public only if it is not
> mentioned in an invariant of the class.
 
I think invariants (explicit or implicit) is why setters and getters
bother me.
 
Either you have a C struct with no invariants, and setters/getters are
just unnecessary OO noise on top of non-OO code.
 
Or you /do/ have invariants, and setting an individual member, at any
time, threatens to break the invariant. Which doesn't mean there can
be /no/ set/get methods, they won't map 1:1 to the members.
 
 
> Instead of asking the object for data and then processing
> the data outside of the object (as when using accessors),
> you should just /tell the object/ to do the processing.
 
Moving logic into the class instead of treating it like a dumb
container. Also good advice (except of course when you /want/
a dumb container).
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Tim Rentsch <tr.17687@z991.linuxsc.com>: Aug 23 05:26AM -0700


> There is a case where a data member is safe to be public: a const
> data member. Access to such a member cannot change a class's
> invariants.
 
My experience with const data members is that they are almost
always more trouble than they're worth. Even in those cases
where a data member is made const, it's better to stick to the
simple rule that data members (other than pure structs) never be
public, on general principles of information hiding: client code
shouldn't know or care what particular data members a class has,
let alone whether they are const or not. Any property an object
wants to supply to its clients should be made available through a
(usually const) member function, and only that, regardless of
whether the property needs an elaborate computation or is simply
returning the value of a data member -- even a const one.
James Kuyper <jameskuyper@alumni.caltech.edu>: Aug 23 08:34AM -0400

On 8/23/19 7:24 AM, Jorgen Grahn wrote:
...
 
> Or you /do/ have invariants, and setting an individual member, at any
> time, threatens to break the invariant. Which doesn't mean there can
> be /no/ set/get methods, they won't map 1:1 to the members.
 
In general, I agree. However, a setter for a single member could make
sense, if the applicable constraints allow two or more different values
for that member, even if all other members are unchanged. For instance,
the invariant might be current_value <= maximum_achieved_value. The
setter for current_value would deal with changes that would violate that
invariant, either by rejecting them or by increasing
maximum_achieved_value (which corresponds to the last case you mention:
a setter that changes two or more members in synchrony).
Jorgen Grahn <grahn+nntp@snipabacken.se>: Aug 23 02:48PM

On Fri, 2019-08-23, Stefan Ram wrote:
>>invariant, either by rejecting them or by increasing
>>maximum_achieved_value (which corresponds to the last case you mention:
>>a setter that changes two or more members in synchrony).
 
When I wrote "map 1:1 to the members" I was more thinking of someone
going through all the members and adding a setter for each of them.
 
> Behind all of this lurks the question: How does one define "setter"?
 
How about "a method that's defined in terms of changing a certain part
of the object, without considering the object as one single entity"?
 
But I suppose that's my definition of a setter I dislike, rather than
of all setters.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Jorgen Grahn <grahn+nntp@snipabacken.se>: Aug 23 03:49PM

On Fri, 2019-08-23, James Kuyper wrote:
> invariant, either by rejecting them or by increasing
> maximum_achieved_value (which corresponds to the last case you mention:
> a setter that changes two or more members in synchrony).
 
I can imagine how that could end up with me breaking out:
 
ValueWithHighwatermark<int> foo = 2; // 2, 2
foo = 3; // 3, 3
foo = 0; // 0, 3
 
I know it was just an example, but my gut feeling is that there
are often solutions like that: to raise the abstraction level
of the members.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Melzzzzz <Melzzzzz@zzzzz.com>: Aug 23 06:07PM

>> public.
 
> There is a case where a data member is safe to be public: a const data
> member. Access to such a member cannot change a class's invariants.
 
Also there is case when member is class with own interface.
 
 
--
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Aug 23 05:12PM +0100

> Lose this signature line and you'll remember me by its absence.
> You've arrange your life just so, even in your rebellion.
 
> But it's not me you're remembering, Leigh. It's Jesus.
 
Far from it as like most sane people I don't read my own .sig when I post
Usenet messages; I had completely forgotten about you until you posted the
fucktarded message I am currently replying to.
 
[spam nonsense snipped]
 
/Flibble
 
--
"Snakes didn't evolve, instead talking snakes with legs changed into
snakes." - Rick C. Hodgin
 
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who
doesn't believe in any God the most. Oh, no..wait.. that never happens." –
Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."
rick.c.hodgin@gmail.com: Aug 23 10:55AM -0700

https://www.youtube.com/watch?v=k5wknazzz9w
 
--
Rick C. Hodgin
ram@zedat.fu-berlin.de (Stefan Ram): Aug 23 01:23PM

>>Or you /do/ have invariants, and setting an individual member, at any
>>time, threatens to break the invariant. Which doesn't mean there can
>>be /no/ set/get methods, they won't map 1:1 to the members.
..
>invariant, either by rejecting them or by increasing
>maximum_achieved_value (which corresponds to the last case you mention:
>a setter that changes two or more members in synchrony).
 
Behind all of this lurks the question: How does one define "setter"?
legalize+jeeves@mail.xmission.com (Richard): Aug 22 11:38PM

[Please do not mail me a copy of your followup]
 
Szyk Cech <szykcech@spoko.pl> spake the secret code
 
>What is easiest to use static C++ code analyser?
 
Probably the easiest one to use is the one built into your C++
compiler.
 
Clang: <https://clang-analyzer.llvm.org/>
MSVC: /analyze
<https://docs.microsoft.com/en-us/cpp/build/reference/analyze-code-analysis?view=vs-2019>
gcc probably has something but nothing is turning up at the moment.
 
Outside of the compiler, I have used cppcheck and it's easy to run
outside of a build. <http://cppcheck.sourceforge.net/>
 
The general advice is to run as many static analyzer tools as you can
because they all have strengths and weaknesses and they haven't yet
converged to have huge overlap, although there is some overlap.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
legalize+jeeves@mail.xmission.com (Richard): Aug 22 11:38PM

[Please do not mail me a copy of your followup]
 
ram@zedat.fu-berlin.de (Stefan Ram) spake the secret code
>>What is easiest to use static C++ code analyser?
 
> Every static code analyzer is easy to use
> (unless you want to use it under Windows).
 
Lies.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
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: