Jack
Jack

Reputation: 16724

Is memset(&mystruct, 0, sizeof mystruct) same as mystruct = { 0 };?

I'm reading about the initialized values by default of an array/struct and have this question:

is memset(&mystruct, 0, sizeof mystruct) same as mystruct = { 0 }; ?

if it's not, what's difference?

Upvotes: 22

Views: 21831

Answers (4)

Keith Thompson
Keith Thompson

Reputation: 263497

memset(&mystruct, 0, sizeof mystruct);

is a statement. It can be executed any time where mystruct is visible, not just at the point where it's defined.

mystruct = { 0 };

is actually a syntax error; { 0 } is not a valid expression.

(I'll assume that mystruct is an object of type struct foo.)

What you're probably thinking of is:

struct foo mystruct = { 0 };

where { 0 } is an initializer.

If your compiler supports it, you can also write:

mystruct = (struct foo){ 0 };

where (struct foo){ 0 } is a compound literal. Compound literals were introduced in C99; some C compilers, particularly Microsoft's probably don't support it. (Note that the (struct foo) is not a cast operator; it looks similar to one, but it's not followed by an expression or parenthesized type name. It's a distinct syntactic construct.)

If your compiler doesn't support compound literals, you can work around it by declaring a constant:

const struct foo foo_zero = { 0 };

struct foo mystruct;
/* ... */
mystruct = foo_zero;

So that's how they differ in syntax and in where you can use them. There are also semantic differences.

The memset call sets all the bytes that make up the representation of mystruct to all zeros. It's a very low-level operation.

On the other hand, the initializer:

struct foo mystruct = { 0 };

sets the first scalar subcomponent of mystruct to 0, and sets all other subcomponents as if they were initialized as static objects -- i.e., to 0. (It would be nice if there were a cleaner struct foo mystruct = { }; syntax to do the same thing, but there isn't.)

The thing is, setting something to 0 isn't necessarily the same thing as setting its representation to all-bits-zero. The value 0 is converted to the appropriate type for each scalar subcomponent.

For integers, the language guarantees that all-bits-zero is a representation of 0 (but not necessarily the only representation of 0). It's very likely that setting an integer to 0 will set it to all-bits-zero, but it's conceivable that it could set it to some other representation of 0. In practice, that would only happen with a deliberately perverse compiler.

For pointers, most implementations represent null pointers as all-bits-zero, but the language doesn't guarantee that, and there have been real-world implementations that use some other representation. (For example, using something like all-bits-one might make null pointer dereferences easier to detect at run time.) And the representation may differ for different pointer types. See section 5 of the comp.lang.c FAQ.

Similarly, for floating-point types, most implementations represent 0.0 as all-bits-zero, but the language standard doesn't guarantee it.

You can probably get away with writing code that assumes the memset call will set all subcomponents to zero, but such code is not strictly portable -- and Murphy's Law implies that the assumption will fail at the most inconvenient possible moment, perhaps when you port the code to an important new system.

Upvotes: 10

Patrick Schlüter
Patrick Schlüter

Reputation: 11841

Theoretically there's a difference. The initialiser is not required to initialise the padding if there is some in mystruct. For example:

int main(void) 
{
     struct mystruct {
          char    a;
          int     what;
     } s = {0};
}

Might contain:

00 xx yy zz 00 00 00 00

where xx yy and zz are undefined bytes that where on the stack. The compiler is allowed to do that. This said, in all practical terms, I haven't encountered a compiler that did that yet. Most sane implementations will semantically handle that case like the memset.

Upvotes: 9

paercebal
paercebal

Reputation: 83364

is memset(&mystruct, 0, sizeof mystruct) same as mystruct = { 0 }; ?

No.

memset(&mystruct, 0, sizeof mystruct) ;

... will tell the compiler to call a function that we expect will set during execution the data in mystruct to zero.

mystruct = { 0 };

... will set tell the compiler set by itself the data to zero, which means it will:

  • if possible, set the data in mystruct to zero at compilation (e.g. for static variables, as tristopia and Oli Charlesworth remarked in the comments)
  • or if not (e.g. auto variables), to generate the assembly code that will set the data to zero when the variable is initialized (which is better than calling a function to do that).

Note that perhaps the compiler could optimize the memset into a compile-time instruction (like replacing the first version with the second version), but I wouldn't rely on that as memset is a function from the runtime library, not some language intrinsic (I'm not a compiler writer/language lawyer, though).

Coming from C++, my own viewpoint is that the more you can do at compilation and the more the compiler knows at compile time, before the execution even starts, the better: It enables the compiler to possibly optimize the code and/or generate warning/errors.

In the current case, using the mystruct = { 0 }; notation to initialize a struct is always safer than using the memset because it is very very easy write the wrong thing in C with a memset without the compiler complaining.

The following examples show that it is easy for the code to do something different than it appears to do:

// only the 1st byte will be set to 0
memset(&mystruct, 0, sizeof(char)) ;          

// will probably overrun the data, possibly corrupting
// the data around it, and you hope, crashing the process.
memset(&mystruct, 0, sizeof(myLARGEstruct)) ; 

// will NOT set the data to 257. Instead it will truncate the
// integer and set each byte to 1
memset(&mystruct, 257, sizeof(mystruct)) ;    

// will set each byte to the value of sizeof(mystruct) modulo 256
memset(&mystruct, sizeof(mystruct), 0) ;      

// will work. Always.
mystruct = { 0 } ;

Upvotes: 25

K-ballo
K-ballo

Reputation: 81379

This is a completely pedantic answer, but given that the internal representation of a null pointer is not guaranted to be 0 the behavior of memset versus brace-initialization would differ (memset would do the wrong thing). That said, I've never heard of an implementation that took on this liberty to have a non all 0 bit pattern for null.

Upvotes: 11

Related Questions