In a C/C++ hybrid project, I found some code that I could reduce to
#include <mem.h>
struct StructContainingDouble
{
double d;
/// other elements omitted
};
void clear(StructContainingDouble* p)
{
memset(p, 0, sizeof *p);
}
without stopping Cppcheck to raise the portability warning
Using memset() on struct which contains a floating point number.
The message is correct, but since the floating-point number is declared double, it seems to be false positive, because in double the (positive) zero value is encoded following the IEEE 754 standard:[*]
0 00000000000 0000000000000000000000000000000000000000000000000000
So I'd tend to simply suppress the warning and forget about it
void clear(ContainingDouble* p)
{
// cppcheck-suppress memsetClassFloat
memset(p, 0, sizeof *p);
}
But maybe there is really a portability issue here?
The actual code is based on the Win32 platform. The structure is used for managing access to shared memory, that's why constructors are useless. And it's not only one object of that structure that has to be zeroed, but an array of it that is embedded in another structure, something like this:
#include <mem.h>
struct Slot
{
double d;
// more members...
};
struct SharedMem
{
Slot slots[2048];
// more members...
};
void clear(SharedMem* p)
{
memset(p, 0, sizeof *p);
}
[*] from: Double-precision floating-point format - Wikipedia
Is it a problem? Yes. No, not really. A very remote maybe.
As pointed out in the comments by interjay C does not mandate format of floating-point values. So in theory 'zeroes' could be an invalid value or not represent zero.
All modern platforms implement IEEE 754 if they have an FPU. Any (likely embedded) system that doesn't will implement IEEE 754 in its library (unless it's a degenerate implementation and simply doesn't have floating-point...).
So while there is no guarantee it's very unlikely you'll encounter a problem here.
There are issues on some platforms regarding fine detail of how precisely they conform to the letter for IEEE 754 but having asked before and never got any answer I'll be excited to here of a platform where memset()
a double with zeroes isn't setting it to the value of zero.
That said, don't forget endianness if you start chopping double up but with zero that's not an issue.
Remember C is getting near to 50 years old and things that are now almost universal such as a byte is 8 bits hadn't settled down and I think quite rightly in order to offer maximum support (don't forget embedded) it's never committed to these standards.
In paranoia mode you could go with:
memset(&obj,0,sizeof obj);
#ifndef __STDC_IEC_559__
obj.dbl_val=0.0;
#endif
Where dbl_val
is the double
member of obj
. However the only likely reason for that to be undefined isn't because block zeroing isn't zero but some other fine point of the standard isn't fully implemented.
I think that the portability considerations have gone too far in this particular case. I have not seen in my life (I do programming for 30+years) any hardware or C implementation where zero means something else than zero. Of course it is possible to create any number format where zero is not zero (for example BDC with the numbers represented by the ASCII digit codes - but it is not the case here), but we discuss the real existing hardware and software.
So IMO memset to zeroes is safe and portable even if the Standard says that the float point numbers are implementation defined, as I do not know any existing implementations where zero means something else than zero, and such implementation would extremely impractical.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With