Re: NULL and zeros



Yevgen Muntyan wrote:
Michael Mair wrote:
Yevgen Muntyan wrote:
Richard Heathfield wrote:
Christopher Layne said:
Richard Heathfield wrote:
[defensive programming yadda yadda]

I meant it is *implied* and was not written because it wasn't relevant to the discussion at hand.

I understood what you meant by "implied", and my previous answer to that point remains valid IMHO.

You clipped my last segment.

Oops.

If a machine expressed integer 0 as all 1 bits internally, and I called
memset(&object, 0, sizeof(object)); that's going to result in object set
to all 0 bits?

Yes, it must. The machine's bizarre internal representation does not excuse the implementation from its obligations. The semantics of memset(&object, 0, sizeof(object)) is "starting at the address indicated by object, set sizeof(object) bytes to the value (unsigned char)0". If object has integer type then that process must have the effect of setting object's value to 0. If it has some other type, however, there is no such requirement.

Standard says in 7.20.3.1: "The calloc function allocates space for an array of nmemb objects, each of whose size
is size. The space is initialized to all bits zero."
It looks like "starting at the address indicated by object, set
> sizeof(object) bytes to the value (unsigned char)0" is your own
interpretation caused by the knowledge of real world computers and
compilers :)

No, unsigned char is _guaranteed_ to have no padding bits. In addition,
it is an unsigned integer type, so the representation of
(unsigned char)0 indeed is "one byte with all bits 0".
So, Richard described it equivalently using his knowledge of the
standard.

Indeed, I was tricked by that wording and inferred that his words imply
that Standard guarantees that

int *a;
int i;
char c = 0;
for (i = 0; i < sizeof (a); ++i)
memcpy (((char*)&a) + i, &c, 1);

is equivalent to

int *a;
memset (&a, 0, sizeof (a))

Make this "unsigned char" instead of "char", then this definitely
is true.
Even
for (i = 0; i < sizeof (a); ++i)
((unsigned char*)&a)[i] = c;
will do.

(or analogous thing with calloc()). What Richard said was indeed
"butter is made of butter", since standard says "all zero bits",
and it says the same about (char)0, and there is no way you can
actually *set* all *bytes* in a structure to (unsigned char)0. (To
that effect you can use memset, memcpy and so on, but does standard
say what it means "to set bytes to zero"?)

Of course there is.
Just use the above with
"struct qux { int foo; double bar; void *baz; } a;"
instead of "int *a;".
The standard indeed does not specify what an "all bytes zero" or "all
bits zero" representation means for non-integral types.
Which is why we are in the position that
struct qux *pQux
createAndInitQux(struct qux *pOptionalInitQux)
{
static const struct qux quxInit = {0};
struct qux *pNew = malloc(sizeof *pNew);
if (NULL != pNew) {
if (NULL == pQux)
*pNew = quxInit;
else
*pNew = *pQux;
}
return pNew;
}
may be a sensible approach.


Anyway, this newsgroup is not comp.std.c is it?

You clearly did not bother to do your "homework", i.e. finding out
what this newsgroup considers topical. I suggest reading
http://clc-wiki.net/wiki/intro_to_clc
and especially
http://clc-wiki.net/wiki/C_community:comp.lang.c:Introduction#topical

Indeed, that says "The group deals with C only to the (narrow) extent
that the ANSI/ISO C Standard defines it.", so my question was off-topic
since I did know standard doesn't guarantee all-zero-bits NULL.

So, when I want to get some knowledge of C programmers out there,
comp.lang.c is a wrong place.

*g* Depends...


So you are playing
games with standard here; you are saying "On some machines, that isn't
the case. If you are excluding such machines, you are in the wrong newsgroup.", and it's no good. Show me chunk of real world code
which will work on any machine covered by standard; or stop pretending
C doesn't mean a programming language used in real world.

Once again: Richard's position is correct for comp.lang.c -- apart
from that, and back to your original question:
- whenever I find some calloc() in someone's code, I assume that
the originator of this calloc() is clueless -- my personal
experience points to this relationship.

Single fact that zeroing memory gives you a crash instead of random
behavior very well justifies using of calloc(), unless it's expensive
(or is there any other objection to using calloc()?).

The problem is that most of the time, people are not aware of
the semantics and think that calloc() saves them each and every
time. Personally, I have never worked with an implementation where
there was more than one null pointer representation or the null
pointer representation was different from all bits zero but I have
worked with platforms where all bits zero did not give you floating
point numbers with value 0.0 -- which sometimes led to doubleplus
unnice debugging orgies when you had to find out why on full moons
the umpteenth whatever seemed to show a slight wobble (in fact, it
was completely off).


- I prefer the "constructor" or "init element" methods for setting
up struct types that may vary during development.

I have init() methods, but they do not allocate memory, that's done
elsewhere, and I get calloc'ed structures, and so on and so forth.
Blah blah blah.
And then in my something_new() methods I like to use calloc() (actually
a wrapper around calloc which will abort if calloc() fails).

If something_new() is always followed by some init() function or
integrates some standard init (like you try with the calloc()),
then you don't need to rely on malloc() plus memset() (calloc()
is nothing else in my eyes).

Note: I do not know your application but aborting most of the time
is _not_ the right thing to do if you have amassed a goodly amount
of data. At least consider adding exit handlers via atexit().


- The compiler may well optimise a malloc() call followed by a
check for NULL followed by an initialisation to effectively all
bits zero by a call to calloc() if deemed necessary.

Again, calloc call happens elsewhere, compiler has no idea about that.
And mind you, "optimise"? Holy standard knows that word? Or you just
using off-topic arguments since conversation is off-topic anyway?

No. I am, from the way this discussion goes on and on, not entirely
sure why you want to keep calloc() but my best guess is that you
you either consider it more convenient (not adding a dedicated 0
initialization) or have some notion of calloc() being "better" or
even "optimal".
I just wanted to point out that "surely it gives you better code"
is not necessarily true.
It is IMO better to write code doing what you _mean_ instead of
code affecting some representation in a way that you think is doing
what you mean.


- In addition, I often have entries that need not be initialised
to zero -- why have the overhead of calloc() to set the respective
bytes to all bits zero?

Overhead is how much exactly? A very simple example: when I need to
scroll in a text widget, I create a structure with some stuff inside,
like what line to scroll to and so on. "Overhead" is exactly zero.

??? It has been some while since I worked in GUI programming so I
do not know what is realistic there (however, I do not understand the
"zero" in your example).
For me, initialisation often _does_ something to at least half of the
members -- initialisation to a "neutral element" is rather seldom in
comparison.

Apart from that: It is possible to write real world programmes that
run on "virtually all" hosted implementations -- implementation limits
may make the programme fail consistently, though.
In addition, one usually strives to keep the portable part of other
programmes as large as possible and isolate non-portable parts in
a couple of headers and/or modules.

Yes, but as I said elsewhere, I am not going not to assume 8 bits
in bytes whenever it's convenient (X likes 8 bits bytes, and there
are cases where you use 8, 16, or 32 as an argument. guess what 8 is).
Of course convenience should not hurt portability. Assuming 8-bits byte
doesn't.

Well, if you can say that for _your_ applications, CHAR_BIT == 8 is
always true and all null-pointers are all bits zero, then add
configuration, compile-time, and startup checks which make sure that
your assumptions are not violated and disallow building your code or
running the programme/using the library in an environment where the
assumptions do not hold.
Then, for you, they are indeed always true.


The question was specifically about existence of machines with certain
properties, for a real world application, not about whether standard
says yes or no about some particular thing.

There are _many_ past threads enumerating machines with null pointers
being not all bits zero. Whether you consider these machines relevant
is your decision. However, your position reads to me "I am making
non-portable assumptions but I think these are not too restrictive
and quite portable for what I want to do -- please confirm this".

Care to read the original question? Very simple. Yes, I did use words
like "do I care", sorry for that, next time I will try to use more
robot language.

I read the original question. The way you phrased it, I understood the
above. I initially assumed that you _did_ read the FAQ beforehand, so
there was no use pointing you to it. I also did not distinctly remember
participating in one of said threads, so me searching for this via
google groups promised to be as effective as you doing it.
From the way you wrote it, I really got the impression that you wanted
some sort of blessing for your assumption.


Without giving us _all_ the data for a well-founded expert placet to
this. The only possible answer can be "it is not portable, so this
practice is ill-advised".

Well, if you really are willing to help and need _all_ the data, you
could for start simply tell if there's a machine with X with NULL not
being all zero bits; as far as I understand there's none.

It took a while for me to make the connection between "X" and "X
Window System", so my answer "none that I know of" is not helpful
at all -- I'd rather asked in a newsgroup or mailing list about "X",
though.


Come on, you care about absolute portability, great. But why tell all
this great stuff about this and that when the question was indeed
simple (I actually thought that there is a strange platform with X
where NULL might not be all zero bits, sorry for not admitting my
stupidity and asking you to forgive me at the very beginning)?

No need to be sarcastic.
If I had understood you correctly and known the answer, I would have
given it to you and pointed you to a place where you could have
verified it.


Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
.