Tuesday, December 31, 2019

Digest for comp.lang.c++@googlegroups.com - 20 updates in 2 topics

Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 31 05:26PM

On Tue, 31 Dec 2019 10:46:30 -0600
> Öö Tiib wrote:
[snip]
 
> > It does not say that bit-wise checks are made,
 
> If NULL == 0, bitwise checks aren't required, just a check of the
> Z flag of the register that received the return.
 
'NULL == 0' will always evaluate to true, by virtue of the definition
of NULL. The bit pattern of the integer literal 0 as null pointer
constant may be different from its bit pattern as an integer, so your
check is meaningless.
James Kuyper <jameskuyper@alumni.caltech.edu>: Dec 31 10:27AM -0800

Ned Latham wrote:
 
> I don't know why you haven't already got it. If NULL == 0 the same
> logic can be used with pointers as with integers and all their bitwidth
> lookalikes and all the functions that require or return those types.
 
NULL is absolutely guaranteed to compare equal to 0 when using any
conforming implementation of C++, regardless of how null pointers are
represented. That's because NULL is required to expand into a null
pointer constant (21.2.3p2). 7.11p1 allows for only two possibilities
for a null pointer constant. The first is that it can be an "integer
literal with a value of zero", which obviously compares equal to 0. The
second is that it can be "a prvalue of type std::nullptr_t". Since the 0
it's being compared with also qualifies as a null pointer constant, they
necessarily compare equal (8.10p4). Therefore, checking whether NULL==0
doesn't give you any information about whether an implementation has
null pointers with all bits set to zero.
This matters if you've made the mistake of relying on things like
calloc() or memset(0) to fill pointer objects with representations of
null pointers. On the flip side, it's not a problem if you're relying
on zero-initialization, since zero-initialization of a pointer is
guaranteed to give it a valid representation of a null pointer(11.6p6,
7.11p1), even if that representation doesn't have all bits 0.
 
> Tests like
 
> if (!(array=calloc(hemeny,sizeof(arrayrcrd)))) // then deal with OOM.
 
> wouldn't work correctly otherwise.
 
Yes they will.
Clause 8.3.1p9 says "The operand of the logical negation operator ! is
contextually converted to bool (Clause 7); its value is true if the
converted operand is false and false otherwise. The type of the result
is bool." 7.14p1 describes the results of converting values to bool. It
says that "A ... null pointer value ... is converted to false ...".
That's true, regardless of how null pointers are represented. Therefore,
this code does precisely what it's supposed to do, regardless of that
representation.
 
Note that this also applies to if(array). In all statements that contain
a condition (other than switch), the condition is "... contextually
converted to bool ..." (9p4). All null pointers, regardless of how they
are represented, convert to a bool value of false, so using a pointer as
a condition always handles null pointer values the way you'd expect,
even if the representation of null values is not what you'd expect
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Dec 31 11:11AM -0800

Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:
[...]
> You have a point so far as concerns, say, memset'ing structs of
> trivial type to all-bits-zero where those structs contain pointers
> which you want to be NULL (should your code actually do that). But you
 
null, not NULL.
 
> pointer constant if calloc fails, and the test for falsity will work
> correctly irrespective of whether the null pointer constant is
> signalled by all-bits-zero.
 
'array' will be a null pointer, not a null pointer constant.
 
A *null pointer constant* is a source code construct (and NULL is a
macro that expands to a null pointer constant). A *null pointer* is a
value that can exist at run time.
 
It's probably OK in most cases to use the term "NULL" to refer to a null
pointer value, but in this case the distinction is a large part of what
we're talking about, so I suggest being a bit more pedantic than usual.
 
 
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
[Note updated email address]
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Dec 31 11:20AM -0800

David Brown <david.brown@hesbynett.no> writes:
[...]
> than, say, "((void*) 0)".
 
> It is not in any way dependent on the representation of null pointers,
> as you probably know.
 
In C, NULL can be defined as 0 or as ((void*)0). In C++, ((void*)0) is
not a valid definition of NULL, because C++'s definition of "null
pointer constant" is more strict than C's.
 
A *null pointer constant* is an integer literal with value zero
or a prvalue of type std::nullptr_t. A null pointer constant
can be converted to a pointer type; the result is the *null
pointer value* of that type and is distinguishable from every
other value of object pointer or function pointer type.
 
(In C++11 and earlier, a integral constant expression with value
0 could be a null pointer constant, but C++14 restricted this to
integer literals. ((void*)0) hasn't been a valid C++ null pointer
constant going back at least to C++98.)
 
But yes, NULL might be usable in a context that requires an integer
value depending on how the implementation defines it. Of course it
would be silly to depend on that.
 
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
[Note updated email address]
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 31 07:47PM

On Tue, 31 Dec 2019 11:11:17 -0800
> > trivial type to all-bits-zero where those structs contain pointers
> > which you want to be NULL (should your code actually do that). But you
 
> null, not NULL.
 
I think you mean that "hold a null pointer value" should replace "be
NULL". If so, I don't object although I think the meaning is clear
enough and you are being somewhat on the pedantic side.
 
 
> A *null pointer constant* is a source code construct (and NULL is a
> macro that expands to a null pointer constant). A *null pointer* is a
> value that can exist at run time.
 
I agree, clumsy language - for one thing, 'array' is neither a
constant nor a literal. As you say, I meant that 'array' will hold a
null pointer value. I doubt anyone misunderstood me however.
 
Jorgen Grahn <grahn+nntp@snipabacken.se>: Dec 31 09:37PM

On Tue, 2019-12-31, Ned Latham wrote:
 
>> except that this does not compiles. Imlicit conversion of int to pointer
>> is not done...
 
> Ok. if ((void*)(i - j) == NULL) // then do whatever.
 
Then rewrite it as
 
if (i==j)
 
and that reason to know extra things about null pointers disappears.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Jorgen Grahn <grahn+nntp@snipabacken.se>: Dec 31 09:54PM

On Mon, 2019-12-30, Öö Tiib wrote:
> actual defects (in non-trivial code on about 50% of cases IME). So
> in review I typically request unit tests and static asserts about
> platform-specific assumptions instead of rewrite.
 
Thanks -- a sane and useful posting in this thread, at last.
(Other postings have been sane, but not useful. Including mine.)
 
I'm going to stop reading now, so my last Usenet read of 2019 is a
good one.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
James Kuyper <jameskuyper@alumni.caltech.edu>: Dec 31 03:21PM -0800

Ned Latham wrote:
> Ok. if ((void*)(i - j) == NULL)
> // then do whatever.
 
Were you under the impression that the left hand side of that comparison was required to be a null pointer value when i==j? There is no such requirement. The requirement you're probably thinking is 7.11p1, but that only applies to integer literals with a value of zero. (i - j) is not an integer literal.
 
Note that even if it does result in a null pointer value, the behavior would still not depend upon representation of null pointer values. NULL is required to expand to a null pointer constant, and the comparison causes it to be converted to void*, resulting in a null pointer value. All null pointer values are required to compare equal, regardless of how they are represented.
 
In any event, what did you expect this line of code to do that couldn't be done more simply and portable by writing if(i == j)?
David Brown <david.brown@hesbynett.no>: Dec 31 06:22PM +0100

On 31/12/2019 18:00, Bonita Montero wrote:
 
>> Are you kidding? -Wall is one of the most basic options one always
>> uses with gcc (together with -Wextra and a bunch of other warning flags).
 
> -Wall includes useful als well as rather useless child-proof locks.
 
Would you like to give some examples? (I realise this will require you
to actually look something up, instead of making up your arguments as
you go along.)
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 06:35PM +0100

>> That's your personal taste and not C++.
 
> What part of "the compiler and flags that I use" made you think it was
> something other than my personal choice?
 
Those which make every warning an error; that's very uncommon
and nerdish.
 
>> kind of aliasing.
 
> Yes, it matters - it matters to people that want to write correct code,
> and not "I know this is crap, but it worked when I tried it" code.
 
The code I have shown works with any compiler.
 
> What you wrote is not particularly common, I think.
 
You think that yout habits are the center of the world.
 
 
 
> Right...
 
> That's because compilers implement C++ based on "Bonita says so"
> rules rather than the standards.  I'll bear that in mind.
 
No, what I wrot is simply common because it is very convenient
over having a union.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 06:46PM +0100

> Would you like to give some examples?  (I realise this will require you
> to actually look something up, instead of making up your arguments as
> you go along.)
 
There are not much, but these are useless:
 
-Wcomment
It's not rare that you first comment out a part with // and
then the outer block with /* */. This isn't really a problem.
-Wenum-compare
Unscoped enums are in the same namespace so they should be
all comparable.
-Wmissing-braces
That's really a useless aesthetic warning.
-Wreorder
It's very rare that the order of initialization-calls counts.
-Wunused-function
This would be disturbing if you would have the function in the
code for a later purpose.
 
But I agree that the vast majority of -Wall-warnings makes sense.
David Brown <david.brown@hesbynett.no>: Dec 31 06:51PM +0100

On 31/12/2019 18:35, Bonita Montero wrote:
>> something other than my personal choice?
 
> Those which make every warning an error; that's very uncommon
> and nerdish.
 
I simply don't think you have experience with quality programming. Some
people write code where bugs are not acceptable. There are many things
required in a development process to achieve a zero bugs (or at least,
as low a chance of bugs as achievable in the time and resource budget).
Heavy use of compiler warnings, and a zero-warning build policy, is a
simple, cheap and commonly used part of that.
 
(Not all code is developed to such standards, of course - otherwise
software would be ridiculously expensive in many cases.)
 
 
>> Yes, it matters - it matters to people that want to write correct
>> code, and not "I know this is crap, but it worked when I tried it" code.
 
> The code I have shown works with any compiler.
 
A "C++ implementation" covers the compiler, library and choice of flags
and options. Sure, the compiler I use could be made to accept the code
you wrote - but not with the flags I require.
 
>> What you wrote is not particularly common, I think.
 
> You think that yout habits are the center of the world.
 
No, I think they are /my/ habits. Some of them are common, some are
uncommon. Some are common in the branch I work in but uncommon in more
general programming. (I find comparisons between different types of
programming arenas to be an interesting topic in these newsgroups.)
 
I don't think casts like yours are common in any area of programming. I
could be wrong here, of course, but that is what I think. If people
whose opinion I respect tell me otherwise, I may change that opinion -
but it is usually extremely difficult to get an idea of what techniques
are common or rare in C++ programming "in general".
 
>> rules  rather than the standards.  I'll bear that in mind.
 
> No, what I wrot is simply common because it is very convenient
> over having a union.
 
Look, the common way of writing the code in question is not to faff
around with casts /or/ unions - you write "if (x < 0)". And people who
are concerned with accurate IEEE floating point, and careful handling of
NaNs and the rest of it, will write "if (signbit(x))". Almost the only
people who care about the representation details of the floating point
types are the ones /implementing/ such functions or macros - and they
can rely on whatever compiler-specific features they want.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 06:59PM +0100

> I simply don't think you have experience with quality programming.
 
Your quality-programming is not a matter of maintainability or if
the code is de-facto guaranteed to work but partitially an aesthetic
baublery.
 
> Some people write code where bugs are not acceptable.
 
What I showed works with any compiler.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 31 06:14PM

On Tue, 31 Dec 2019 16:13:57 +0000 (UTC)
 
> If you don't know what type you'll have at a given point in code then
> that is what templates were invented for. They're also more flexible than
> variants.
 
First, the purpose of variants is not to provide an alternative to
templates for polymorphic code. Their main purpose is to allow values
of a limited set of alternative types to be passed in a type safe way.
 
Secondly, variants are constructed from templates. Templates are not
"more flexible than variants": they are different things. Variants
test the contained type within the permitted set of types at run time
by reference to an index or tag; templates discriminate their types at
compile time (which includes trying to instantiate a variant with a
type not within its permitted variant set, which will give a compile
time error).
 
> >avoid the responsibility of creating, tracking and destroying them.
 
> No true. Unless you use the visit() horror then you need to know the index
> position or type of what you want to access.
 
If you need to interrogate the variant at run time to find out what
it holds you can use std::variant::index (std::holds_alternative and
std::get_if are also available). But in almost all real-life cases,
you want to use std::visit.
 
You have an astonishing lack of knowledge about C++. Almost everything
you post is wrong.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 07:16PM +0100

> compile time (which includes trying to instantiate a variant with a
> type not within its permitted variant set, which will give a compile
> time error).
 
Is this a nonsense-pettifogging-contest here?
Paavo Helde <myfirstname@osa.pri.ee>: Dec 31 08:30PM +0200

On 31.12.2019 19:46, Bonita Montero wrote:
 
> -Wcomment
> It's not rare that you first comment out a part with // and
> then the outer block with /* */. This isn't really a problem.
 
Your description does not match what this warning is doing. It warns
about /* inside /*. Usually it is easy to fix, replace inner /* with //.
 
> -Wenum-compare
> Unscoped enums are in the same namespace so they should be
> all comparable.
 
I think this is a really useful comment. If I have mixed up my enums I
would want to know that.
 
> -Wmissing-braces
> That's really a useless aesthetic warning.
 
Never seen that warning. Probably because I take care to write my
initializers.
 
> -Wreorder
> It's very rare that the order of initialization-calls counts.
 
This is the only one which I agree with. It should not warn if the
initializer is a constant expression, at least.
 
> -Wunused-function
> This would be disturbing if you would have the function in the
> code for a later purpose.
 
So you are checking in untested code.
 
 
> But I agree that the vast majority of -Wall-warnings makes sense.
 
ok
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 07:44PM +0100

>>   all comparable.
 
> I think this is a really useful comment. If I have mixed up my enums I
> would want to know that.
 
That's a child-proof lock.
 
>>   That's really a useless aesthetic warning.
 
> Never seen that warning. Probably because I take care to write my
> initializers.
 
It's rare but useless.
 
>>   This would be disturbing if you would have the function in the
>>   code for a later purpose.
 
> So you are checking in untested code.
 
I'll check it later and that's quite ok.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 31 06:48PM

On Tue, 31 Dec 2019 19:16:50 +0100
> > type not within its permitted variant set, which will give a compile
> > time error).
 
> Is this a nonsense-pettifogging-contest here?
 
So you really think that
 
"If you don't know what type you'll have at a given point in code
then that is what templates were invented for. They're also more
flexible than variants"
 
is an accurate discription of the purpose of variants and templates.
 
If so, you are as clueless as Boltar. Have you ever used discriminated
unions in your programming life? (Clearly Boltar hasn't)
"Öö Tiib" <ootiib@hot.ee>: Dec 31 12:23PM -0800

On Tuesday, 31 December 2019 19:36:08 UTC+2, Bonita Montero wrote:
> > something other than my personal choice?
 
> Those which make every warning an error; that's very uncommon
> and nerdish.
 
People with infantile reactions how rules of project they join
are so very "uncommon" and "nerdish" are soon back on streets
searching for project with more "common" and "dumboish" rules.
Daniel <danielaparker@gmail.com>: Dec 31 12:29PM -0800

On Tuesday, December 31, 2019 at 1:48:50 PM UTC-5, Chris Vine wrote:
> > > run time by reference to an index or tag
 
> > Is this a nonsense-pettifogging-contest here?
 
> So you really think that <quote from bol...>
 
I think Bonita is permitted to question your wording in the quote above,
without a suggestion that that implies bol...'s position :-)
 
Daniel
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.

Re: 財富列車

新年对联_百度搜索
James C. Hsiung
Professor of Politics & Int'l Law
New York University
19 West 4th St.
New York, N.Y.
(212) 998-8523


On Mon, Dec 30, 2019 at 9:31 PM Tina Soong <tinasoong@att.net> wrote:
Subject: Fwd: Fw:  財富列車

新年快樂!歲歲平安!🙏🙏🙏👍👍👍❤️❤️❤️
jch (熊 玠)鞠躬

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

Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 30 11:59PM

On Mon, 30 Dec 2019 19:58:52 +0000
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
[snip]
> std::holds_alternative() are not constexpr unless the variant is
> constexpr.
 
> At some point I must take the time to work out how it is done.
 
On reflection, impressive but perhaps not super-impressive. At the
conceptual level, std::visit (if it had access to std::variant's
privates) could static_cast the address of the start of the variant's
storage to the appropriate type conditional upon the variant's index
variable (or whatever tag variable the variant keeps), and pass that
(dereferenced) to the visitor function. This would be resolved at run
time, after which ordinary function overload resolution would kick in
for the visitor function.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 03:13AM +0100

> fall foul of the type-based access rules of C and C++.  You can only
> access data via an lvalue of appropriate type (a compatible type, or a
> char type).  Anything else is not defined by the standards.
 
There is no compiler and there won't be any compiler that behaves
different here.
You're not a practical programmer but a theorist.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 03:29AM +0100

> will be occasions where the compiler can generate tighter code on
> the assumption that types like "int" and "float" never share the
> same address. ...
 
No, that won't happen. The compiler sees in my case that I alias
a float as an unsigned and doesn't do any optimization around that.
James Kuyper <jameskuyper@alumni.caltech.edu>: Dec 30 10:16PM -0500

> Paavo Helde <myfirstname@osa.pri.ee> wrote:
>> On 29.12.2019 20:30, boltar@nowhere.org wrote:
>>> On Sun, 29 Dec 2019 12:21:33 +0200
...
> int ifru_media;
> int ifru_intval;
> caddr_t ifru_data;
 
How does that declaration prove your point? It doesn't involve any
examples of "write as one type and read as another'.
Also,on Unix platforms, the C compiler is part of the same
implementation that provides those headers. The reason why portable code
should avoid "write as one type and read as another' is that the
behavior of such code is undefined (except in C2011). The implementors
KNOW what form the undefined behavior of such code takes on their
platform, and therefore can write code which relies upon that behavior.
Code intended to be portable can't do that.
 
Also, don't you find it a bit odd that what you consider to be "the
whole point of a union" has always had undefined behavior in C++, and
had undefined behavior in C all the way up until C2011? If the C and C++
committees had considered that "write as one type and read as another"
to be the whole point of unions, or even just the main point, or even
just a commonplace usage, you would think they would have explicitly
defined what the behavior of such usage was. In fact, the main point of
unions was originally the ability to store objects of multiple different
types in the same piece of memory, so long as the storage periods didn't
overlap.
 
It wasn't until C2011 that a footnote was added to the C standard
identifying that the behavior of "write as one type and read as another"
is to reinterpret the associated memory as having the type of the lvalue
used to read it. This still makes it completely dependent upon the
implementation-defined representation of the two types involved, so it
still can't be used in code that's intended to be portable, but the new
wording does allow it be used in code that doesn't need to be portable.
 
Footnotes are non-normative, and I've been unable to locate any
corresponding normative text in the C standard. People who should know
claim that this can be derived from other things the standard says about
obect representations, but when I asked for the details of that
derivation, all I got in response was silence. However, I haven't
bothered complaining much about it, because that's what most people have
always expected, what most C and C++ compilers have actually done, and
the footnote makes it clear that this is the C committee's intent - so
the absence of supporting normative text isn't a particularly important
problem.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Dec 30 07:37PM -0800

On 12/30/2019 9:12 AM, David Brown wrote:
[...]
 
> behaviour and many compilers (including gcc, clang and msvc) /will/ make
> you suffer for such language abuse.
 
>> But that's pure theory.
 
I must be missing your main point, however there is a nice case where
casting is "okay"?:
________________________
#include <iostream>
 
struct foo
{
int a;
};
 
 
struct bar
{
foo f;
int b;
};
 
 
int main() {
bar b = { { 0 }, 1};
foo* f = (struct foo*)&b;
 
f->a += 1;
b.b += 1;
 
std::cout << "b.f.a = " << b.f.a << "\n";
std::cout << "b.b = " << b.b << "\n";
 
return 0;
}
________________________
 
All pod, and perfectly fine to cast a pointer to a struct bar into a
pointer to a struct foo.
 
struct foo is the _first_ member of struct bar.
Siri Cruise <chine.bleu@yahoo.com>: Dec 30 08:07PM -0800

In article <qucif8$1oa0$1@gioia.aioe.org>, boltar@nowhere.org
wrote:
 
 
> Oh dear, someone better tell the authors of the standard unix networking
> libraries then. Clearly they have no clue, I mean look at this horror from
> net/if.h:
 
If your contract for C source code demands it conform to ANS C,
if.h violates the contract. If the contract has some different
requirement, like compatiable with gcc -lplugh2.77.1, then maybe
if.h is okay. If the contract requires Ada, you ain't even close.
 
There's no international treaty of C Standard Compliance. You
choose what you and the customers agree to.
 
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
The first law of discordiamism: The more energy This post / \
to make order is nore energy made into entropy. insults Islam. Mohammed
Siri Cruise <chine.bleu@yahoo.com>: Dec 30 08:30PM -0800

In article <queeiv$iqr$1@dont-email.me>,
 
> implementation-defined representation of the two types involved, so it
> still can't be used in code that's intended to be portable, but the new
> wording does allow it be used in code that doesn't need to be portable.
 
typedef enum {
BigEndian = 0,
HoneywellEndian = 1,
PDPEndian = 2,
LittleEndian = 3
};
#define nativeByteOrder ( \
((union{char b[4]; uint32_t n;}){.b={
LittleEndian, HoneywellEndian, \
PDP11Endian, BigEndian}}).n & 0xFF)
#define bigEndian (nativeByteOrder==BigEndian)
#define honeywellEndian (nativeByteOrder==HoneywellEndian)
#define pdpEndian (nativeByteOrder==PDPEndian)
#define littleEndian (nativeByteOrder==LittleEndian)
 
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
The first law of discordiamism: The more energy This post / \
to make order is nore energy made into entropy. insults Islam. Mohammed
boltar@nowhere.org: Dec 31 09:23AM

On Mon, 30 Dec 2019 14:57:25 +0100
 
>So this is C code (not C++) for a specific compiler on a specific
>operating system. As gcc has always defined the behavior, it "just
>works" there.
 
Its from MacOS so its compiled with Clang.
boltar@nowhere.org: Dec 31 09:25AM

On Mon, 30 Dec 2019 16:39:03 +0100
>type-punning in C.
 
>But when you claim that this is the /only/ use, outside tiny embedded
>systems, you are talking drivel.
 
So other than the VERY occasional uses of saving memory or reducing the amount
pushed onto a stack in a function call/return, what would you say is the main
use for a union then?
 
>Type-punning through unions is defined in C standards, but referencing
>examples from its use in C says nothing about unions in C++.
 
Many C header files and source code will be included into a C++ project. In
any sane world C++ *will* support the same union rules as C because it has
to regardless of whatever the standards committee in their ivory tower say.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 31 11:19AM

On Mon, 30 Dec 2019 19:37:05 -0800
 
> All pod, and perfectly fine to cast a pointer to a struct bar into a
> pointer to a struct foo.
 
> struct foo is the _first_ member of struct bar.
 
The point being made was I think about type punning, which leads to
trouble with C and C++'s strict aliasing rules.
 
There is no type punning in your code. It so happens that the address
of a standard-layout struct has two dynamic types (in C, effective
types): that of the struct and that of its first member, and so on
recursively if the first member is also a standard-layout struct. You
can freely cast between these and freely dereference the result, without
breaking strict aliasing, because a constructed object of the
dereferenced type will actually exist at the address in question: this
has always been the case in C++, but C++17 introduced a new term
"pointer-interconvertible"[1] to cover this.
 
Chris
 
[1] According to C++17 "If two objects are pointer-interconvertible,
then they have the same address, and it is possible to obtain a pointer
to one from a pointer to the other via a reinterpret_cast".
Melzzzzz <Melzzzzz@zzzzz.com>: Dec 31 12:00PM


> So other than the VERY occasional uses of saving memory or reducing the amount
> pushed onto a stack in a function call/return, what would you say is the main
> use for a union then?
 
In C++11 you can use objects in union....
 
 
> Many C header files and source code will be included into a C++ project. In
> any sane world C++ *will* support the same union rules as C because it has
> to regardless of whatever the standards committee in their ivory tower say.
 
Depends on compiler...
 
--
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Svi smo svedoci - oko 3 godine intenzivne propagande je dovoljno da jedan narod poludi -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala
David Brown <david.brown@hesbynett.no>: Dec 31 01:01PM +0100

On 31/12/2019 03:13, Bonita Montero wrote:
 
> There is no compiler and there won't be any compiler that behaves
> different here.
> You're not a practical programmer but a theorist.
 
Again, you are wrong. Type-based alias optimisations are used on many
compilers, and they can give unexpected results from code that uses
inappropriate conversions like this. As I said, in simple test code you
often get the results that you'd expect if you did not know about the
effective type rules. But I have seen contrary results from MSVC, gcc
and clang - /all/ of these have type-based alias analysis optimisations
that can give you unexpected results when you don't understand (or
ignore) the rules of the language. This is not "just theory" - it is
practice. (It is not easy to get this effect on MSVC, but it does happen.)
 
It is so much "real world practice" that the Linux kernel is complied
with "-fno-strict-aliasing" to turn off type-based alias analysis -
because their code abuses types and accesses in a way that conflicts
with the standards.
 
It is incomprehensible to me how some people react with denial of
reality to things like this. It is fair enough to say "I wish C and C++
allowed casts like this" or "my code will only work on compilers like
gcc -fno-strict-aliasing because it messes with pointer types". But to
blindly say "I know this is against the rules of the language, but I'll
do it anyway because I think it should be allowed" takes a special kind
of stubborn stupidity.
 
 
If you want to write knowingly incorrect code, that's up to you. But
please do not recommend it to others.
 
 
Let's demonstrate with a simple example of type-based alias
optimisation. It's a little different from your example, because it's
simpler to demonstrate the issue without a lot of extra surrounding
code, and it can be handled simply in <https://godbolt.org>. And it
applies equally to C and C++.
 
 
int foo(int * px, float * py) {
int x = *px;
*py = 0;
return x + *px;
}
 
gcc -O2 -fno-strict-aliasing gives:
 
foo:
mov eax, DWORD PTR [rdi]
mov DWORD PTR [rsi], 0x00000000
add eax, DWORD PTR [rdi]
ret
 
With that flag, the compiler adds semantics to the C (or C++) language
to allow accessing data via non-compatible pointers or references. That
means it has to re-read via px, just in case py pointed to the same address.
 
Without the special flag, you get:
 
foo:
mov eax, DWORD PTR [rdi]
mov DWORD PTR [rsi], 0x00000000
add eax, eax
ret
 
It is more efficient code, based on the (valid) assumption that a
pointer to int and pointer to float can't refer to the same object.
 
 
MSVC /O2 gives:
 
int foo(int * __ptr64,float * __ptr64) PROC
; foo, COMDAT
mov r8d, DWORD PTR [rcx]
mov DWORD PTR [rdx], 0
mov eax, DWORD PTR [rcx]
add eax, r8d
ret 0
 
MSVC does not do this kind of type-based optimisation in this case, and
reads through px twice. Maybe I haven't used powerful enough
optimisation flags here.
 
 
ICC -O2 gives:
 
foo(int*, float*):
mov eax, DWORD PTR [rdi] #3.14
add eax, DWORD PTR [rdi] #5.17
mov DWORD PTR [rsi], 0 #4.6
ret
 
Bizarrely, icc re-reads via px, but does so out of order - giving code
that is less efficient than gcc but still dependent on type-based alias
analysis (and more efficient than gcc -fno-strict-aliasing).
Paavo Helde <myfirstname@osa.pri.ee>: Dec 31 02:06PM +0200


> So other than the VERY occasional uses of saving memory or reducing the amount
> pushed onto a stack in a function call/return, what would you say is the main
> use for a union then?
 
There is no other use, at least not according to the C++ standard. Its
usefulness can be "VERY occasional" or "sometimes useful", which
basically mean the same if you remove the emotional dressing. I think
nobody claims union is the most important construct in C++.
 
This is also related to the zero overhead principle. If there is no
reason to allocate any extra bytes for the object, the C++ language must
provide means to avoid that, in order to maintain zero overhead.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 01:13PM +0100

> Again, you are wrong.
 
No, there isn't any compiler and there wont be ever any compiler
where what I wrote doesn't work.
.
 
> Type-based alias optimisations are used on many compilers, and
> they can give unexpected results from code that uses inappropriate
> conversions like this.
 
Not what I wrote: in this case the compiler does see the aliasing.
 
> *py = 0;
> return x + *px;
> }
 
That's a totally different issue.
David Brown <david.brown@hesbynett.no>: Dec 31 01:14PM +0100

On 31/12/2019 04:37, Chris M. Thomasson wrote:
 
> All pod, and perfectly fine to cast a pointer to a struct bar into a
> pointer to a struct foo.
 
> struct foo is the _first_ member of struct bar.
 
The cast is fine - often when dealing with these things, the cast itself
is perfectly valid. It is accessing data through the cast result that
is in question.
 
And in this case, I believe it is perfectly valid - the address of a
struct is guaranteed (in C, and I think also in C++ for POD with no
virtual stuff) to be the address of its first member.
David Brown <david.brown@hesbynett.no>: Dec 31 01:38PM +0100


> So other than the VERY occasional uses of saving memory or reducing the amount
> pushed onto a stack in a function call/return, what would you say is the main
> use for a union then?
 
I'd say it is used for three things:
 
1. To avoid pointlessly wasting memory. PC's may have oodles of ram,
but they have small caches. Small unions don't even need to go into
memory - compilers optimise them like any other data.
 
2. To express "sum types" - a type that can be one of several other
types. (structs are "product types" in the same sense.)
 
3. For type punning.
 
 
If you know you need either an A or a B, but not both, it simply doesn't
make sense to have a type holding both (like a struct). You have
something like a union. In C++, a std::variant makes this safer, and
makes it easier to keep track of the construction and destruction of the
objects. With a union, you have to do the tracking manually. Either
way, you avoid having objects that you don't need or want - and thus
avoid the responsibility of creating, tracking and destroying them.
 
 
> Many C header files and source code will be included into a C++ project. In
> any sane world C++ *will* support the same union rules as C because it has
> to regardless of whatever the standards committee in their ivory tower say.
 
No, that is not an issue.
 
Header files will often have declarations of union types - either as
independent types, or specifically for parameters to functions or APIs.
But they will rarely contain code that /uses/ the union, and does any
type-punning. You can use the union for non-type-punning access in the
C++ code that includes the header, and for type-punning access in the C
code that implements the functions declared in the header. That's all
fine and standards-compliant.
 
 
Many C++ compilers /do/ support type-punning for POD unions, just
because it is simple to support and occasionally useful to programmers.
But they would not have to do so.
David Brown <david.brown@hesbynett.no>: Dec 31 02:09PM +0100

On 31/12/2019 13:13, Bonita Montero wrote:
>> Again, you are wrong.
 
> No, there isn't any compiler and there wont be ever any compiler
> where what I wrote doesn't work.
 
This is not guaranteed. It won't work with the compiler/flag
combination I use, since it will be rejected as a fatal error when you
try to compile the code.
 
>> they can give unexpected results from code that uses inappropriate
>> conversions like this.
 
> Not what I wrote: in this case the compiler does see the aliasing.
 
It might - and it might not, depending on how code is re-arranged,
broken up, transferred around. And even if the compiler /does/ see the
aliasing, there is no guarantee it will honour it.
 
I fully agree that it is highly unlikely for a compiler to interpret the
exact code you wrote in any way other than the way you intended it. But
for serious programming, "highly unlikely" is not good enough.
 
Similar code, with the same fundamental error you made, could easily end
up interpreted differently.
 
And I totally fail to understand how you could think it's okay to break
the rules because you think "no one will notice if I break them just a
little bit".
 
Your code is wrong. Broken. A good compiler can see that and warn
about it.
 
>>      return x + *px;
>> }
 
> That's a totally different issue.
 
No, it is the same issue. It is a different bit of code, because it is
easier to show the trouble it can cause, but it is the same underlying
issue - the same paragraph in the standards.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 02:12PM +0100

>> No, there isn't any compiler and there wont be ever any compiler
>> where what I wrote doesn't work.
 
> This is not guaranteed.
 
This de-facto guaranteed.
 
> It won't work with the compiler/flag combination I use, ..
 
This absolutely hasn't anything to do with the aliasing-options
of the compiler; at least with the code I showed.
 
> It might - and it might not, ...
 
It will definitely, you compulsive pettifogging idiot.
 
> I fully agree that it is highly unlikely for a compiler to interpret
> the exact code you wrote in any way other than the way you intended it.
 
Theres for sure a lot of code that is like what I showed so that no
compiler-vendor can ignore this.
 
>> That's a totally different issue.
 
> No, it is the same issue.
 
No, that's a different issue because of the lack of the opportunity
to detect the aliasing.
Ned Latham <nedlatham@woden.valhalla.oz>: Dec 30 05:29PM -0600

Keith Thompson wrote:
 
----snip----
 
> Is that the whole point of showing us that code, that it depends
> on a null pointer being represented as all-bits-zero because it
> uses calloc()?
 
No. Try reading with your eyes open.
 
Idiot.
 
> sending us on a wild goose chase digging through some online code.
 
> I'll probably never know, because I won't waste my time talking to
> someone who calls people idiots.
 
Do you waste time talking to people who misrepresent what they've been
given and then sneer at it?
 
----snip----
James Kuyper <jameskuyper@alumni.caltech.edu>: Dec 30 09:42PM -0500

On 12/30/19 6:01 PM, Ned Latham wrote:
> James Kuyper wrote:
>> Ned Latham wrote:
...
>> to. Can you give me the exact location in that body of code of at least
>> one such construct? Better yet, could you quote that line of code?
 
> No. get off your arese and look.
 
Why? It shouldn't take you more than a few seconds to honor my request,
while it might take me hours to honor yours.
The fundamental problem is that I won't even necessarily recognize what
you're referring to, even if it's staring me in the face. There's a
pretty good chance that what you think is code that depends upon the
representation of null pointers is, in fact, not so dependent.
Alternatively, it might be code that I incorrectly think has no such
dependence - either way, I won't recognize it when I see it. However, if
you would just identify the particular code you're talking about, which
should only take you a few seconds, it might save me hours of possibly
fruitless searching, and we can move on to the discussion of whether or
not you're correct, and whether or not it was actually necessary to
write such code.
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Dec 30 09:48PM -0800

>> uses calloc()?
 
> No. Try reading with your eyes open.
 
> Idiot.
 
It's not worth my time to read your code to try (and quite possibly
fail) to figure out what you're talking about. And it's no longer
worth my time to interact with you at all.
 
*Plonk*
 
[...]
 
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
[Note updated email address]
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
Ned Latham <nedlatham@woden.valhalla.oz>: Dec 31 06:03AM -0600

James Kuyper wrote:
 
----snip----
 
> you're referring to, even if it's staring me in the face. There's a
> pretty good chance that what you think is code that depends upon the
> representation of null pointers is, in fact, not so dependent.
 
I don't know why you haven't already got it. If NULL == 0 the same
logic can be used with pointers as with integers and all their bitwidth
lookalikes and all the functions that require or return those types.
Tests like
 
if (!(array=calloc(hemeny,sizeof(arrayrcrd)))) // then deal with OOM.
 
wouldn't work correctly otherwise.
 
Knowing the way NULL is represented can be useful.
 
----snip----
David Brown <david.brown@hesbynett.no>: Dec 31 01:57PM +0100

On 31/12/2019 00:22, Ned Latham wrote:
 
>> because it is written in a sort-of C, sort-of C++, sort-of something
>> else mix using your own macros.
 
> That's noi reason for saying "incomplete".,
 
That is not why I said it was incomplete. I said it was incomplete
because you linked to some source code that relied on non-standard
headers that were not included in your links.
 
 
>>> The documentation tells you that. And why.
 
>> No, it does not.
 
> Don't lie to me about what I wrote, you fuck.
 
Throwing your toys out the pram does not help your argument.
 
 
>>> Don't be stupider than you have to be, David.
 
>> They are not defined in the source code you linked.
 
> So? The statement is dead stupid.
 
It is /correct/. You said "look at the source code in this link", and I
did. I saw it was incomplete, and said so. I could certainly make a
reasonable guess about how you defined macros like "WHILE", but I could
not be sure what else might be missing. And there is a limit to how
much effort I'll put in deciphering spaghetti that mixes includes and
conditional compilation like your code.
 
>> the file "mcdef.h", which was not in the links (it is in the tarball
>> that can be found by a little digging from your links).
 
> There's a link to it in the documentation.
 
That would be the documentation that was not included in the original
links, but which I found by digging around?
 
Perhaps you sent the wrong links, or have not looked at the links for
some time.
 
>> Macros to try to make your C or C++ code like BASIC are /not/ a good
>> idea, and never have been.
 
> "BASIC"? You're a moron.
 
IF no tail THEN return NULL;
 
It's not quite BASIC, but it's C code with macros to make it look like
BASIC.
 
Maybe you had another language in mind, rather than BASIC - but not C or
C++.
 
 
 
>> Had you linked to the documentation, it would have told me that.
 
> Hmph. All you had to do to see the whole site is use BS and ENTER in
> the location bar.
 
It didn't take me much digging - I did not suggest it was difficult to
find. But if you had intended for people to read the documentation it
would have made sense to link to it.
 
 
>> It says nothing about /why/ that might be a useful idea.
 
> You're insane. Why would type-indepedence *not* be useful?
 
When it leads to inefficient and unsafe code, like yours?
 
>>> Exceptions are evil, especially in low-level code.
 
>> RAII is orthogonal to exceptions.
 
> It's bloat.
 
Please explain.
 
>> enough for code from 1995 - but hardly examples of how to write C++ in
>> this generation.
 
> Mclib's not about C++.
 
So you agree it is not written in normal C++ ?
 
 
>> Yes, you mentioned that in your documentation. It was one of many
>> incorrect statements.
 
> Dream on, Bozo.
 
No, thanks, I will try to leave it at that - I have no plans to try to
list your mistakes. People can read your posts in this thread and guess.
Andrew Z <formisc@gmail.com>: Dec 30 08:01PM -0800

hello,
im attempting to simplify the C code for arduino/idf framework.
the setup_task function worked well until i introduced the Zap class. And now it is failing with :
[code]
 
rc/main.cpp: In function 'void setup()':
src/main.cpp:112:115: error: invalid use of non-static member function
setup_task(outlet.OutletToggleTask, (char*)"Outlet Task", eventGroup, outlet.OutletCallback, outlet.GetCycleTicks);
^
In file included from src/main.cpp:19:0:
 
[/code]
 
I appreciate the guidance and any help since I clearly don't understand what is wrong. I found a similar thread here (https://forum.arduino.cc/index.php?topic=524167.0). But im not sure why there is a need to create such a complex hierarchy...
 
simplified code:
[code]
main.cpp
#include <Arduino.h>
...
#include <zap.h>
#define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( xTimeInMs ) * ( configTICK_RATE_HZ / ( TickType_t ) 1000 ) )
const int TIME_BIT = BIT0 ;
#define DATA_PIN 4
#define CHANNEL 1
 
 
EventGroupHandle_t eventGroup;
 
void setup_task( void (*DeviceTask)(void*), char* TaskName, EventGroupHandle_t eventGroup,
void (*Callback_Fn)(TimerHandle_t), TickType_t cycle_ticks ) {};
 
void setup(){
 
eventGroup = xEventGroupCreate(); //check if NULL NOT returned.
Zap outlet(DATA_PIN, CHANNEL , 20000); // make a new outlet instance with
setup_task(outlet.OutletToggleTask, (char*)"Outlet Task", eventGroup, outlet.OutletCallback, outlet.GetCycleTicks); // <-- Failure here
 
....
}
 
zap.h
#ifndef _ZAP_H
#define _ZAP_H
#include <Outlet.h>
 
class Zap : public Outlet {
private:
int channel ; //= 1 ; //CHANNEL 1
const TickType_t t_outlet_cycle ;
const TickType_t t_outlet_cycle_ticks = 10000;
public:
Zap( int pin , int ch=1, TickType_t cycle_ms = 10000 ): Outlet(pin), channel {ch} , t_outlet_cycle {cycle_ms}
{
assert( cycle_ms >= 10000) ;
 
} ;
 
void OutletCallback(TimerHandle_t handle) ;
void OutletToggleTask( void *Params) ;
int GetChannel() { return channel ; } ;
TickType_t GetCycle () { return t_outlet_cycle ;} ;
TickType_t GetCycleTicks () { return t_outlet_cycle_ticks ;} ;
};
 

Monday, December 30, 2019

Digest for comp.lang.c++@googlegroups.com - 1 update in 1 topic

Ned Latham <nedlatham@woden.valhalla.oz>: Dec 30 05:22PM -0600

David Brown wrote:
>> David Brown wrote:
>>> Keith Thompson wrote:
>>>> Ned Latham writes:
 
----snip----
 
> I only looked at the source code you linked - it is not complete,
 
Bullshit.
 
> because it is written in a sort-of C, sort-of C++, sort-of something
> else mix using your own macros.
 
That's noi reason for saying "incomplete".,
 
>>> as other people know it.
 
>> The documentation tells you that. And why.
 
> No, it does not.
 
Don't lie to me about what I wrote, you fuck.
 
>>> and the like, which are not defined anywhere.
 
>> Don't be stupider than you have to be, David.
 
> They are not defined in the source code you linked.
 
So? The statement is dead stupid.
 
> They are defined in
> the file "mcdef.h", which was not in the links (it is in the tarball
> that can be found by a little digging from your links).
 
There's a link to it in the documentation.
 
> thinks it helps to make one programming language look like another.
> Macros to try to make your C or C++ code like BASIC are /not/ a good
> idea, and never have been.
 
"BASIC"? You're a moron.
 
>> be totally independent of type (past, present and future). Pointers can do
>> that; templates cannot. They're a code bloat idea, anyway.
 
> Had you linked to the documentation, it would have told me that.
 
Hmph. All you had to do to see the whole site is use BS and ENTER in
the location bar.
 
> It says nothing about /why/ that might be a useful idea.
 
You're insane. Why would type-indepedence *not* be useful?
 
----idiocy snipped----
 
 
>> Those are design decisions too, idiot. The C++ library throws exceptions.
>> Exceptions are evil, especially in low-level code.
 
> RAII is orthogonal to exceptions.
 
It's bloat.
 
> was widely available. Some of your design decisions are reasonable
> enough for code from 1995 - but hardly examples of how to write C++ in
> this generation.
 
Mclib's not about C++.
 
>> behaviour.
 
> Yes, you mentioned that in your documentation. It was one of many
> incorrect statements.
 
Dream on, Bozo.
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.

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

James Kuyper <jameskuyper@alumni.caltech.edu>: Dec 30 06:03AM -0800

Ned Latham wrote:
> James Kuyper wrote:
...
 
> http://www.users.on.net/~nedlatham/Software/mclib/Documents/sourcecode.html
 
> Check AVLC and ListC, also read
> http://www.users.on.net/~nedlatham/Software/mclib/Documents/mclists.html
 
That is not the kind of response I was asking for. Let me be more explicit:
I'm looking for a single C++ construct, from a single line of code, that
you were only able to use because of what you know about how null pointers
are represented on the target implementation. That is, inherently, a
construct that would not produce the desired result if the code were ported
to an implementation that uses a different way to represent null pointers.
It's fine if you need to provide additional lines of code, or even system
documentation, to provide the proper context for that construct. However,
I need you to actually identify the particular construct you're referring
to. Can you give me the exact location in that body of code of at least
one such construct? Better yet, could you quote that line of code?
David Brown <david.brown@hesbynett.no>: Dec 30 05:24PM +0100

On 30/12/2019 12:20, Ned Latham wrote:
 
>> I had a quick look at the code - for the sake of your sanity, don't read
>> it.
 
> Well, if you're not going to read any documentation, why bother indeed.
 
You didn't link to documentation - you linked to the source code. The
source code was, of course, the important part for the discussion. (I
found the document pages too.)
 
 
>> I don't know what language Ned is trying to use,
 
> Using, David. mclib is a working C++ library. Has been for at least ten
> years.
 
I only looked at the source code you linked - it is not complete,
because it is written in a sort-of C, sort-of C++, sort-of something
else mix using your own macros.
 
>> but it is not C++
>> as other people know it.
 
> The documentation tells you that. And why.
 
No, it does not.
 
 
>> (Hint - it is full of macros like WHILE and IF
>> and the like, which are not defined anywhere.
 
> Don't be stupider than you have to be, David.
 
They are not defined in the source code you linked. They are defined in
the file "mcdef.h", which was not in the links (it is in the tarball
that can be found by a little digging from your links).
 
There are few thinks more irritating to programmers than some nitwit who
thinks it helps to make one programming language look like another.
Macros to try to make your C or C++ code like BASIC are /not/ a good
idea, and never have been.
 
 
 
> The documentation would have told you that AVLC and ListC are designed to
> be totally independent of type (past, present and future). Pointers can do
> that; templates cannot. They're a code bloat idea, anyway.
 
Had you linked to the documentation, it would have told me that. It
says nothing about /why/ that might be a useful idea. (A reasonable
answer would be "the code is from 1995, when C++ compilers had limited
and inefficient support for templates".)
 
 
>> free? Ned doesn't.)
 
> Those are design decisions too, idiot. The C++ library throws exceptions.
> Exceptions are evil, especially in low-level code.
 
RAII is orthogonal to exceptions. You can use one feature without the
other, though they work well together.
 
I can appreciate that your code was written before non-throwing "new"
was widely available. Some of your design decisions are reasonable
enough for code from 1995 - but hardly examples of how to write C++ in
this generation.
 
 
 
> And BTW, it's calloc(), not malloc(). Linux malloc() has a tendency to
> return "optimistic" pointers, which for my purposes is an unreliable
> behaviour.
 
Yes, you mentioned that in your documentation. It was one of many
incorrect statements.
David Brown <david.brown@hesbynett.no>: Dec 30 05:27PM +0100

On 30/12/2019 11:19, Ned Latham wrote:
 
> What you've got is working code and documentation describing it. The AVLC
> Specification document details three funcions that take void* parameters
> and also return void*, Extract(), Find(), Insert().
 
Even though you apparently have no intention of answering Keith's
questions sensibly, could you at least say why you think a function
returning void* is dependent on the representation of null pointers?
 
Your documentation says your code relies on void* being the same size as
int. I didn't see anything in the code that actually depends on that
(but I have not gone through it in detail) - but that bears no direct
relationship on the representation of null pointer constants.
Ben Bacarisse <ben.usenet@bsb.me.uk>: Dec 30 06:16PM


> David Brown wrote:
<cut>
>> [...] New and delete rather than malloc and free?
 
I suspect this is the heart of the problem.
 
> Those are design decisions too, idiot. The C++ library throws exceptions.
> Exceptions are evil, especially in low-level code.
 
> And BTW, it's calloc()
 
You assume that null pointers are represented with all-bits-zero because
you want to use calloc, and you want to use calloc because you think new
will throw an exception. (If you know about non-throwing new then I
can't see any reason for not using it, thereby allowing null pointers to
dealt with by a constructor as C++ intended.)
 
Also your test for null pointers being all-bits-zero (as provided by
calloc) is flawed:
 
#ifndef NULL
#define NULL 0
#elif (NULL != 0)
#error NULL is defined as non-zero!