'When is memset to 0 nonportable? [duplicate]
From this comment in GCC bug #53119:
In C,
{0}
is the universal zero initializer equivalent to C++'s{}
(the latter being invalid in C). It is necessary to use whenever you want a zero-initialized object of a complete but conceptually-opaque or implementation-defined type. The classic example in the C standard library ismbstate_t
:mbstate_t state = { 0 }; /* correctly zero-initialized */
versus the common but nonportable:
mbstate_t state; memset(&state, 0, sizeof state);
It strikes me as odd that the latter version could be unportable (even for implementation-defined types, the compiler has to know the size). What is the issue here and when is a memset(x, 0, sizeof x)
unportable?
Solution 1:[1]
memset(p, 0, n)
sets to all-bits-0.
An initializer of { 0 }
sets to the value 0.
On just about any machine you've ever heard of, the two concepts are equivalent.
However, there have been machines where the floating-point value 0.0 was not represented by a bit pattern of all-bits-0. And there have been machines where a null pointer was not represented by a bit pattern of all-bits-0, either. On those machines, an initializer of { 0 }
would always get you the zero initialization you wanted, while memset
might not.
See also question 7.31 and question 5.17 in the C FAQ list.
Postscript: One other difference, as pointed out by @ryker: memset
will set any "holes" in a padded structure to 0, while setting that structure to { 0 }
might not.
Solution 2:[2]
The reason for this has to do with how types are represented.
Section 6.7.9p10 of the C standard describes how fields are initialized as follows:
If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static or thread storage duration is not initialized
explicitly, then:
if it has pointer type, it is initialized to a null pointer;
if it has arithmetic type, it is initialized to (positive or unsigned) zero;
if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;
if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized to zero bits
And p21 also states:
If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration
The difference between this and setting all bytes to zero is that some of the above values may not necessarily be represented by all bits zero.
For example, there are some architectures where the address 0 is a valid address. This means that a null pointer is not represented as all bits zero. (Note: (void *)0
is specified as a null pointer constant by the standard, however the implementation will treat this as whatever the representation of a null pointer is)
The standard also doesn't mandate a particular representation for floating point types. While the most common representation, IEEE754, does use all bits 0 to represent the value +0, this is not necessarily true for other representations.
Solution 3:[3]
Noting a difference in behavior between the two methods...
In ...= {0};
if padding bytes exist, they will not be cleared.
But a call to memset()
will clear padding.
From here
"Possible implementation of mbstate_t is a struct type holding an array representing the incomplete multibyte character, an integer counter indicating the number of bytes in the array that have been processed, and a representation of the current shift state."
In the case mbstate_t
is implemented as a struct
it is notable that {0}
will not set padding bytes that may exist to zero
, making the following assumption debatable:
mbstate_t state = { 0 }; /* correctly zero-initialized */
memset()
however does include padding bytes.
memset(state , 0, sizeof state);//all bytes in memory region of test will be cleared
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 |