is it safe to zero float array with memset?

  • Thread starter 69dbb24b2db3daad932c457cccfd6
  • Start date
G

Gordon Burditt

Not necessarily if you use the results afterward *as floats* or *as
Well, yes and no. I mean, when I was using DOS (more than a decade
ago), an important pointer was the one at the interrupt vector table,
or the video memory (0x0000 and 0xA000 if I remember), and it was
always done by setting a ptr to a number. Resetting the IVT by
memsetting, was dangerous, but if you wanted to do some tricks, it was
a possible choice.

But since C does not guarantee that this same code will work on a
PDP-11, it's not safe. "undefined behavior" doesn't guarantee that
it won't do exactly what you expect it to do (until, of course, the
boss is watching).
The meaning of what it contains, should be of no concern for C, as it's
a matter of the implementation itself.

If it's a matter of the implementation itself, *IT'S NOT SAFE*.
Whether you're accessing a non-readable memory by deferencing a weird
ptr, it's again the implementation, but setting the ptr still results
in a safe operation. Writing and even reading to that location is,
naturally, not safe.

Setting the pointer *AND THEN USING (but not DEREFERENCING) IT*
isn't safe. The following can possibly abort the program:

char *p = 0xdeadbeef; /* or some other oddball hex constant */

p; /* note that I didn't say *p here */

Note, for example, that in protected mode putting certain bit
patterns into a segment register on an i386 platform cause traps
without even trying to dereference anything.

For floats, again, NaN may be a result of a misinterpretation of what
the float was meant to be, but it cannot be considered unsafe from C
point of view.

Anything that is not guaranteed to be safe from the C point of view
is unsafe from the C point of view.
It's the programmer who must be sure of all the meanings :)

Gordon L. Burditt
 
S

Sensei

But since C does not guarantee that this same code will work on a
PDP-11, it's not safe. "undefined behavior" doesn't guarantee that
it won't do exactly what you expect it to do (until, of course, the
boss is watching).

I see.
Setting the pointer *AND THEN USING (but not DEREFERENCING) IT*
isn't safe. The following can possibly abort the program:

char *p = 0xdeadbeef; /* or some other oddball hex constant */

p; /* note that I didn't say *p here */

Yes, and even reading from p can cause an abort.
Note, for example, that in protected mode putting certain bit
patterns into a segment register on an i386 platform cause traps
without even trying to dereference anything.

Yes, what I'm saying is that, as long as you don't mess with memory
addresses (*), and as long as you don't give a meaning to the floats,
it's safe, not meaningful, completely random, but safe. While using
those values just because you trust your god, then Murphy's laws will
give you a good lessons :)



(*) I said in fact, ``you don't read from it (or write)'', i.e. any use
of it is dangerous, since it involves reading and/or writing...
 
M

Malcolm

Keith Thompson said:
If I found that memset() really is faster, *and* that the increase in
performance is actually significant,
I was going to make that point. However the OP said it was faster, so I
decided to take it as a given. In fact, as Eric Sosman pointed out,
situations in which zeroing memory is the bottleneck are fairly rare.
I'd probably write a test
function, to be invoked once at program startup, that checks whether
0.0 really is all-bits-zero. If it isn't, it would abort the program.
That's quite a good I idea. The problem with the way I work is that I tend
to have lots of functions and files which I shift between programs. So the
"superfast matrix multiply", which does need a lightning fast zeroing
operation, might be called from three or four separate main()s.
 
M

Malcolm

Richard Heathfield said:
Just to help you sleep well tonight, I can assure you that you are 100%
correct, which makes a change around here. (I've just been reading today's
feed, and what a sorry collection of articles it is.)
I've noticed that a lot of the talented regs seem to have disappeared.

I'm thinking of starting a series on "how to use C effectively" that goes
beyond details of the standard to look more at the software engineering side
of C programming.

Do you think that would attract people back?
 
K

Krishanu Debnath

Keith Thompson wrote:

[snip]
void set_float_zero(float *dest, size_t count)
{
static int initialized = 0;
int may_use_memset;

if (!initialized) {
may_use_memset = float_zero_is_all_bits_zero();
initialized = 1;
}

if (may_use_memset) {
memset(dest, 0, count * sizeof *dest);
}
else {
size_t i;
for (i = 0; i < count; i ++) {
dest = 0.0;
}
}
}

[snip]

Interestingly, the compiler I tried (gcc 3.4.4) warned that
"`may_use_memset' might be used uninitialized in this function". In
fact, the use of the "initialized" variable guarantees that this won't
happen, but the compiler wasn't able to figure this out. You can


No, you are actually accessing uninitialized may_use_memset on second
call
of 'set_float_zero' function. may_use_memset should be a static
variable.

Krishanu
 
K

Keith Thompson

Krishanu Debnath said:
Keith Thompson wrote:

[snip]
void set_float_zero(float *dest, size_t count)
{
static int initialized = 0;
int may_use_memset;

if (!initialized) {
may_use_memset = float_zero_is_all_bits_zero();
initialized = 1;
}

if (may_use_memset) {
memset(dest, 0, count * sizeof *dest);
}
else {
size_t i;
for (i = 0; i < count; i ++) {
dest = 0.0;
}
}
}

[snip]

Interestingly, the compiler I tried (gcc 3.4.4) warned that
"`may_use_memset' might be used uninitialized in this function". In
fact, the use of the "initialized" variable guarantees that this won't
happen, but the compiler wasn't able to figure this out. You can


No, you are actually accessing uninitialized may_use_memset on second
call
of 'set_float_zero' function. may_use_memset should be a static
variable.


Good catch, thanks.

In case anybody wants to use this code, here it is again with the
error corrected.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

static int float_zero_is_all_bits_zero(void)
{
float f = 0.0;
unsigned char zero_bytes[sizeof f] = { 0 };
return memcmp(&f, zero_bytes, sizeof f) == 0;
}

void set_float_zero(float *dest, size_t count)
{
static int initialized = 0;
static int may_use_memset;

if (!initialized) {
may_use_memset = float_zero_is_all_bits_zero();
initialized = 1;
}

if (may_use_memset) {
memset(dest, 0, count * sizeof *dest);
}
else {
size_t i;
for (i = 0; i < count; i ++) {
dest = 0.0;
}
}
}

#define ARR_LEN 1000

int main(void)
{
float *arr = malloc(ARR_LEN * sizeof *arr);
set_float_zero(arr, ARR_LEN);
return 0;
}
 
C

Chris Croughton

For that matter, as long as I'm messing with the build procedure, I
might as well have it set a macro that indicates whether memset() is
safe, and use that in the code to determine at compilation time which
method to use.

The only problem with this is that it's difficult to find a platform
on which 0.0 *isn't* all-bits-zero, so any code that assumes it isn't
may not be tested properly.

The other big problem is that such a platform may well be used with
cross-compilation, and runnng the test program on the target may well
not be possible at build time.

If the test can be done at runtime, I would tend to have it set a flag
so that the "clear an array of floats" function could determine which
algorithm is fastest and do it that way. That's what a number of
libraries have done, for instance with systems which may or may not have
floating point processors (another method, especially if there are
several functions depending on the same thing, is to use a jump or
function pointer table and select the right one at startup).

Chris C
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,167
Messages
2,570,911
Members
47,453
Latest member
MadelinePh

Latest Threads

Top