Do you need a zero initialization for structs in D? - d

The C way is to memset() the structure, because by default it is considered filled with garbage. In C++ you do = {0} to zero initialize.
addrinfo hints;
memset (&hints, 0, sizeof (struct addrinfo));
What is a D way for zero initialization?

It automatically initializes based on its contents, which are usually zeros (but notably not for char or float family, which are set to nan values, unless you set them to =0 in the struct definition, on the individual fields)..
So, usually, you don't need to explicitly initialize D structs, the compiler will do it automatically for you and if it isn't doing the right thing, you should set it on the struct definition itself. If you can't change the definition though and do specifically need zeros, you can still use the C memset function.
foo f = void; // skip normal initialization
import core.stdc.string;
memset(&f, 0, f.sizeof); // set to 0 with memset

Related

How do I properly initialize 'struct stat' using C++11?

For years I have been initializing my struct stat like this:
#include <sys/stat.h>
struct stat foo = {0};
Specifically, that {0} set all the fields to zero, equivalent to memset (&foo, NULL, sizeof foo);. Now with C++11, this has started yielding warnings:
foo.cpp:2:19: warning: missing field 'st_mode' initializer [-Wmissing-field-initializers]
struct stat s = {0};
^
This is because of the new initializer syntax of C++11, and the warning implies I am not initializing all members. What is the preferred way to instantiate and initialize a struct stat in C++11?
Use
stat s{};
instead and it will do the job without any warnings. It is called value-initialization of the object. Although in your case struct stat foo = {0}; should perform aggregate initialization (assuming your struct stat is an aggregate), and the remaining members should be value-initialized also, so technically the code is correct.
If your compiler is older and doesn't support struct s{} syntax, you might still be able to use C99 syntax: struct stat s = { .st_dev = 0 }; Failing even that, or if you have to wipe one, memset( &s, 0, sizeof(struct stat) ); will always work.
Could this stem from a case of misunderstanding {0}? You know that the 0 doesn't actually mean "set all fields to zero", right? It means "set the first field to zero" ... and all the other ones are left to the whim of the language (which, as it happens, will zero-initialise them anyway).
struct stat foo = {} would more accurately describe your intention, and I suspect it would also take care of the warning.
Of course, nowadays, you can be absolutely clear by writing struct stat foo{};.

Designated Initializers in C99: How to handle empty uninitialized struct members in C11?

Since in C I can call the members of a struct by name (myStruct.myMember = ) I was wondering what I would do in C++ with those members that are not initialized.
So as I understood, C++ does not support this kind of initialization:
static struct usb_endpoint_descriptor fs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16 (64),
};
But when I use correct syntax, how do I handle members that are not initialized?
Let's say I want bDescriptorType uninitialized. Do I set it to NULL?
static struct usb_endpoint_descriptor fs_source_desc = {
USB_DT_ENDPOINT_SIZE,
NULL,
USB_ENDPOINT_XFER_BULK,
__constant_cpu_to_le16 (64)
};
Or is there any way in C++ to initialize the structure's members by their name?
how do I handle members that are not initialized?
The feature you describe is called designated initializers and was introduced in C99. It is not supported by C++. All members that are not initialized explicitly are guaranteed to be set to zero (*).
Maybe you didn't consider it, but the same applies to regular struct initialization as well. Example:
typedef struct
{
int a;
int b;
} ab;
ab mystruct = { .a = 1 }; // a is 1, b is guaranteed to be 0
ab mystruct = { 1 }; // a is 1, b is guaranteed to be 0
(The last example is also true for C++.)
This language rule is the reason why we can initialize all elements in a struct/array to zero by typing:
ab mystruct = { 0 };
because it actually means "set a to zero, and let then all other elements be implicitly initialized to zero".
(*) Formally, they are initialized as if they had static storage duration, i.e. data gets set to zero, pointers get set to NULL etc. C11 6.7.9/10.
If you use C++, then use constructors. Init by NULL is more C-way really.
And no, there is no standard C++ way to use named parameters (something like boost::parameters may help, but there is no need to it here).
Your case may be something like
struct usb_endpoint_descriptor
{
usb_endpoint_desctiptor(type bL, type bAttr, type wSize) :
bLength(bL), bAttributes(bAttr), wMaxPacketSize(wSize) {}
type bLength;
type bDescriptorType;
type bmAttributes;
type wMaxPacketSize;
};
However, it's bad style to leave variables not-initialized in C++.
So, if you use C structure, you can
1) Write C++ wrapper.
2) Write derived class.
3) Initialize field, that you don't want to initialize with some default value.
FYI, All of the previous answers were correct. there was no support for designated initializers in C++... until C++20.
C++20 added aggregate initializers in that version of the C++ standard.
The syntax is different than C99 dot notation because, I guess the standard committee wanted the syntax to be more idiomatically Cplusplussesque.
Here is an on point stack overflow question
Designated initializers in C++20
And here is a popular reference site. https://en.cppreference.com/w/cpp/language/aggregate_initialization

Only one array without a size allowed per struct?

I was writing a struct to describe a constant value I needed, and noticed something strange.
namespace res{
namespace font{
struct Structure{
struct Glyph{
int x, y, width, height, easement, advance;
};
int glyphCount;
unsigned char asciiMap[]; // <-- always generates an error
Glyph glyphData[]; // <-- never generates an error
};
const Structure system = {95,
{
// mapping data
},
{
// glyph spacing data
}
}; // system constructor
} // namespace font
} // namespace res
The last two members of Structure, the unsized arrays, do not stop the compiler if they are by themselves. But if they are both included in the struct's definition, it causes an error, saying the "type is incomplete"
This stops being a problem if I give the first array a size. Which isn't a problem in this case, but I'm still curious...
My question is, why can I have one unsized array in my struct, but two cause a problem?
In standard C++, you can't do this at all, although some compilers support it as an extension.
In C, every member of a struct needs to have a fixed position within the struct. This means that the last member can have an unknown size; but nothing can come after it, so there is no way to have more than one member of unknown size.
If you do take advantage of your compilers non-standard support for this hack in C++, then beware that things may go horribly wrong if any member of the struct is non-trivial. An object can only be "created" with a non-empty array at the end by allocating a block of raw memory and reinterpreting it as this type; if you do that, no constructors or destructors will be called.
You are using a non-standard microsoft extension. C11 (note: C, not C++) allows the last array in a structure to be unsized (read: a maximum of one arrays):
A Microsoft extension allows the last member of a C or C++ structure or class to be a variable-sized array. These are called unsized arrays. The unsized array at the end of the structure allows you to append a variable-sized string or other array, thus avoiding the run-time execution cost of a pointer dereference.
// unsized_arrays_in_structures1.cpp
// compile with: /c
struct PERSON {
unsigned number;
char name[]; // Unsized array
};
If you apply the sizeof operator to this structure, the ending array size is considered to be 0. The size of this structure is 2 bytes, which is the size of the unsigned member. To get the true size of a variable of type PERSON, you would need to obtain the array size separately.
The size of the structure is added to the size of the array to get the total size to be allocated. After allocation, the array is copied to the array member of the structure, as shown below:
The compiler needs to be able to decide on the offset of every member within the struct. That's why you're not allowed to place any further members after an unsized array. It follows from this that you can't have two unsized arrays in a struct.
It is an extension from Microsoft, and sizeof(structure) == sizeof(structure_without_variable_size_array).
I guess they use the initializer to find the size of the array. If you have two variable size arrays, you can't find it (equivalent to find one unique solution of a 2-unknown system with only 1 equation...)
Arrays without a dimension are not allowed in a struct,
period, at least in C++. In C, the last member (and only the
last) may be declared without a dimension, and some compilers
allow this in C++, as an extension, but you shouldn't count on
it (and in strict mode, they should at least complain about it).
Other compilers have implemented the same semantics if the last
element had a dimension of 0 (also an extension, requiring
a diagnostic in strict mode).
The reason for limiting incomplete array types to the last
element is simple: what would be the offset of any following
elements? Even when it is the last element, there are
restrictions to the use of the resulting struct: it cannot be
a member of another struct or an array, for example, and
sizeof ignores this last element.

Someone is using the struct name as a variable name too. What does the code really say?

This morning we found an old chunk of code that was causing a library call to crash.
struct fred
{
int a;
int b;
int c;
};
fred fred[MAX_SIZE+1];
memset( fred, 0, sizeof(fred) * MAX_SIZE+1 );
It appears that the sizeof(fred) may have been the full array size, rather than the structure size, as it was overwriting a great deal of memory.
The fact that it compiled without warning on several different systems seemed odd.
Is there a correct semantic for this case where the type and variable name are colliding?
or is this some sort of undefined behavior? or just a defect?
Number one would be, don't do this as it's confusing - but you've already discovered this.
The variable hides the name of the struct, but you can still use struct fred to refer to the type.
e.g.
fred fred[MAX_SIZE+1];
memset( fred, 0, sizeof(struct fred) * (MAX_SIZE+1) );
Alternatively, why not just use the size of the complete object. That way your memset call is robust in the face of changes to either the array size or type. You can do:
memset( fred, 0, sizeof fred );
You must have the parentheses when using a type id with sizeof but it's not needed when you use an object.
Shouldn't this be sizeof(fred)*(MAX_SIZE+1) since your array is MAX_SIZE+1 long?
The latest declaration takes precedence:
[C++03: 9.1/2]: A class definition introduces the class name into the scope where it is defined and hides any class, object, function, or other declaration of that name in an enclosing scope (3.3). If a class name is declared in a scope where an object, function, or enumerator of the same name is also declared, then when both declarations are in scope, the class can be referred to only using an elaborated-type-specifier (3.4.4).
An elaborated-type-specifier is when you stick struct or class at the front of the type; this effectively disambiguates it, though, strictly speaking, and due to the above cited rule, the lookup was never really ambiguous in the first place.
So:
void foo()
{
struct bar {};
bar bar[5];
memset(bar, 0, sizeof(bar));
// ^^^^^^^^^^^
// 5
memset(bar, 0, sizeof(struct bar));
// ^^^^^^^^^^^^^^^^^^
// 1
}
// (NB. Exact sizes may differ; 1 and 5 given as relative examples only)
The fact that this is all well-defined is one reason that you didn't get a warning. Still, I'd hope that an intelligent compiler would spot your code as a possible programmer mistake — rationalising about why some given implementation does or does not emit some given warning in some non-mandated case, though, is largely folly.
When you define the variable, it hides the name of the type, so yes, when you do sizeof(fred), you're getting the size of the array, not the size of the struct. it's pretty easy to verify this by simply printing out sizeof(fred).
The short answer, however, is just: "don't do that."
With the exception of run-time sized cases, the typical idiomatic way to use memset (as well as memcpy, malloc, etc.) is to do
memset(dst_ptr, 0, sizeof *dst_ptr);
or, equivalently,
memset(&dst_object, 0, sizeof dst_object);
Which is how it should have been used in this case as well
memset(&fred, 0, sizeof fred);
and the problem with the name conflict would not arise. The memset(fred, 0, sizeof fred) variant will work as well.

C Static Array Initialization - how verbose do I need to be?

To initialize an int array with all zeros, do I need to use:
int foo[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Or, will this work:
int foo[10] = {0};
In C/C++ if you initialize just the first element of an array of known size with a value, the remainder will be zero-filled, so:
int foo[10] = {0};
will do exactly what you want.
This also works for structs:
struct bar {
int x;
int y;
char c;
} myBar = {0};
will initialize all members to 0.
The standard (C99 - 6.7.8/12 - Initialization) says this:
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.
In C the grammar requires that there be at least one 'assignment-expression' inside the braces. An 'assignment-expression' can be many things from a constant or identifier up through much more complex expressions. However, an empty string doesn't qualify as an 'assignment-expression', so there has to be something between the braces.
In C++, the grammar specifically allows the '{ }' initializer, so the following would also zero-initialize the array:
int foo[10] = {};
It's probably also worth noting that in C++ the entries that don't have a specific initializer value in the initialize list will be 'value-initialized' or 'default-initialized' which might be different than being zero-initialized depending on what the constructors for the variable type are and whether the compiler is following the C++98 standard or the C++03 standard (this is probably the only difference of any significance between C++98 and C++03). The whole situation with value vs. default initialization is rather complicated, so if you're interested see this answer: Do the parentheses after the type name make a difference with new?.
Fortunately, the difference doesn't seem to cause much trouble in practice, although if you run into it, it would probably cause some head scratching for a while when trying to figure out what the behavior really should be. I usually don't really think much about it - it makes my head hurt.
int foo[10] = {0};
This is very fine :)
Note that if you do the following:
int foo[10] = {1};
Only the first element of the array will be initialized with the non-zero number whereas the rest will be initialized with zeros.
all elements not mentioned in the initializer will be initializes to that types zero value where applicable.
So int foo[10] = {0}; is fine, the remaining elements not mentioned will also be 0
Wow, C kind of seems to be simple, but even after years of citing the specification it's amazing how something new can still turn up.
I just looked it up in the first edition spec (ANSI/ISO 9899-1990) and, sure enough, the remainder of an auto aggregate is specified (6.5.7) "If there are fewer ... initialized implicitly...".
So: Anything non-auto. Always 0 (or, as initialized) whether initialized or not.
Auto: completely initialized if you initialize any elements at all, otherwise, not initialized.