Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 is mbstate_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?

like image 990
Felix Dombek Avatar asked Nov 30 '21 13:11

Felix Dombek


People also ask

Is memset faster than fill?

memset can be faster since it is written in assembler, whereas std::fill is a template function which simply does a loop internally.

Does memset check for NULL?

AFAIK memset isn't required to check for NULL, so if the malloc fails you'll zero size bytes starting from address 0.

Does memset write to memory?

memset() will blindly write to the specified address for the number of specified bytes, regardless of what it might be overwriting. It is up to the programmer to ensure that only valid memory is written to.

Why does memset take an int?

memset predates (by quite a bit) the addition of function prototypes to C. Without a prototype, you can't pass a char to a function -- when/if you try, it'll be promoted to int when you pass it, and what the function receives is an int .

What is Memset() used for?

The most common application of memset () is to set a block of memory to "all 0 bytes" so as to erase any information that memory previously contained.

Is Memset() faster than set all elements to 0?

Depending on the implementation of memset () and the size of the block of memory being zeroed, this can be faster than simply setting all elements to 0 in code. (memset () is usually implemented in assembly language, and can use operations such as the x86 "string" instructions or the ARM "multiple register store" to speed it up.)

What is the meaning of (Str + 13) after Memset?

After memset (): GeeksForGeeks........programming geeks. Explanation: (str + 13) points to first space (0 based index) of the string “GeeksForGeeks is for programming geeks.”, and memset () sets the character ‘.’ starting from first ‘ ‘ of the string up to 8 character positions of the given string and hence we get the output as shown above.

What is bit blit in Memset?

Many versions of memset can use a "bit blit" operation in hardware to set large groups of memory to the same value essentially instantly - or at least far faster than you could possibly do with a code-level loop - especially if you're setting the value to zero or 0xFF. How can one use memset () in C++ for two dimensional arrays?


Video Answer


3 Answers

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.

like image 179
Steve Summit Avatar answered Oct 17 '22 14:10

Steve Summit


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.

like image 45
dbush Avatar answered Oct 17 '22 14:10

dbush


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
like image 34
ryyker Avatar answered Oct 17 '22 12:10

ryyker