I was wondering if someone could provide a detailed, simple explanation of the differences between the two of the following pieces of code. Given the following definition:
typedef struct {
stuff;
stuff_2;
} variable_t;
What is the difference between:
variable_t my_variable;
variable_t my_variable = {};
And if I do the first one, and then never fully initialize it, why does the compiler not throw an error?
Note: I am compiling with gcc -std=gnu99, so the second is valid and wound up being the solution to a problem that I had. I was wondering as to why.
It depends a little bit on where you place the respective variable definition, and it also seems depends on the compiler in use.
Automatic storage duration
Let's discuss the difference when the variables have automatic storage duration (which is the case if you place it in function or block scope and there without static keyword):
void someFunction() {
variable_t my_variable; // (1)
variable_t my_variable = {}; // (2)
}
(1) denotes a variable definition without an explicit initialization. And according this online C standard draft, it's value is indeterminate:
If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate.
(2) is a variable definition with explicit initialization through an initializer list without designators, i.e. without associating values to members through their names but only through the order of values (cf. 6.7.9 p17..21).
The interesting paragraph is 6.7.9 p21, which states that if the initializer list has fewer entries than the number of struct members, the members are initialized according to the initialization rule of static storage duration (i.e. to 0 or NULL as explained later):
If there are fewer initializers in a brace-enclosed list than there
are elements or members of an aggregate, ... , the remainder of the
aggregate shall be initialized implicitly the same as objects that
have static storage duration.
So it seems that if you write variable_t my_variable = {}, then all members are initialized to 0 or NULL.
However, as mentioned by aschepler in the comments, C initialization list grammar states that initializer lists must not be empty (cf. also cppreference.com):
... the initializer must be a non-empty, brace-enclosed,
comma-separated list of initializers for the members
So according to the standard an initializer list in C needs at least one entry; When testing it in my XCode8.3 environment with -std=gnu99, an empty initialization list seems to be supported, but I am aware that this is not a valid reference. So to be safe and not to depend on particular compiler extensions, you should actually write:
variable_t my_variable = {0};
Static storage duration
At file scope, your variable definitions will have static storage duration, and then other rules apply (cf. 6.7.9 (10)):
(10) ... 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;
...
(21) If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, ... the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
So if you write...
#include <stdio.h>
variable_t my_variable; // (1)
variable_t my_variable = {}; // (2)
then (1) and (2) actually yield the same result because for the not explicitly initialized variable (1), paragraph (10) applies, and for the explicitly but empty initialized variable (2), according to paragraph (21), every member falls back to the initialization rule of (10).
Again, compilers may not support empty initalization lists as discussed above.
Hope it helps (because it has been a lot of typing :-) )
When you declare:
variable_t my_variable; // a variable_t that is uninitialized
variable_t my_variable = {}; // a variable_t initialized with zeroes.
Note that for variables declared at file-scope, this doesn't really matter since the data is - normally- zeroed out before program start.
Used on the stack, the second line efficiently fills my_variables with zeroes. Same as if there was a call to:
memset(&variable, 0, sizeof(variable));
This works because, in C, you can copy a structusing =.
Here's a little game the computer is sure to win.
struct A { /*...*/ };
void main()
{
A a; // random
A b = {};
if (memcmp(&a, &b, sizeof(A)) == 0)
{
printf("You win\n");
return;
}
a = b;
if (memcmp(&a, &b, sizeof(A)) == 0)
{
printf("I win\n");
}
}
Related
Is it allowed to take the address of an object on the right hand-side of its definition, as happens in foo() below:
typedef struct { char x[100]; } chars;
chars make(void *p) {
printf("p = %p\n", p);
chars c;
return c;
}
void foo(void) {
chars b = make(&b);
}
If it is allowed, is there any restriction on its use, e.g., is printing it OK, can I compare it to another pointer, etc?
In practice it seems to compile on the compilers I tested, with the expected behavior most of the time (but not always), but that's far from a guarantee.
To answer the question in the title, with your code sample in mind, yes it may. The C standard says as much in §6.2.4:
The lifetime of an object is the portion of program execution during
which storage is guaranteed to be reserved for it. An object exists,
has a constant address, and retains its last-stored value throughout
its lifetime.
For such an object that does not have a variable length array type,
its lifetime extends from entry into the block with which it is
associated until execution of that block ends in any way.
So yes, you may take the address of a variable from the point of declaration, because the object has the address at this point and it's in scope. A condensed example of this is the following:
void *p = &p;
It serves very little purpose, but is perfectly valid.
As for your second question, what can you do with it. I can mostly say I wouldn't use that address to access the object until initialization is complete, because the order of evaluation for expressions in initializers is left unsepcified (§6.7.9). You can easily find your foot shot off.
One place where this does come through, is when defining all sorts of tabular data structures that need to be self referential. For instance:
typedef struct tab_row {
// Useful data
struct tab_row *p_next;
} row;
row table[3] = {
[1] = { /*Data 1*/, &table[0] },
[2] = { /*Data 2*/, &table[1] },
[0] = { /*Data 0*/, &table[2] },
};
6.2.1 Scopes of identifiers
Structure, union, and enumeration tags have scope that begins just after the appearance of
the tag in a type specifier that declares the tag. Each enumeration constant has scope that
begins just after the appearance of its defining enumerator in an enumerator list. Any
other identifier has scope that begins just after the completion of its declarator.
In
chars b = make(&b);
// ^^
the declarator is b, so it is in scope in its own initializer.
6.2.4 Storage durations of objects
For such an [automatic] object that does not have a variable length array type, its lifetime extends
from entry into the block with which it is associated until execution of that block ends in
any way.
So in
{ // X
chars b = make(&b);
}
the lifetime of b starts at X, so by the time the initializer executes, it is both alive and in scope.
As far as I can tell, this is effectively identical to
{
chars b;
b = make(&b);
}
There's no reason you couldn't use &b there.
The question has already been answered, but for reference, it doesn't make much sense. This is how you would write the code:
typedef struct { char x[100]; } chars;
chars make (void) {
chars c;
/* init c */
return c;
}
void foo(void) {
chars b = make();
}
Or perhaps preferably in case of an ADT or similar, return a pointer to a malloc:ed object. Passing structs by value is usually not a good idea.
I am trying to understand different ways linux kernel initialize structures. In this query I wrote a sample usb driver but I do not understand some points, pointed as comments preceding ??
static struct usb_device_id pen_table[] = //?? why pen_table is an array
{
{ USB_DEVICE(0xaaaa , 0x8816) }, //??what type of array initialization is this
{} /* Terminating entry */ //??how this terminates
};
I tried to initialize device id table in this way, but I am getting errors as near initialization
static struct usb_device_id pen_table = {
.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
.idVendor=0xaaaa,
.idProduct = 0x8816,
};
You should have Linux kernel source at hand to really understand this.
Why pen_table is an array?
It wil be necessary in MODULE_DEVICE_TABLE (see Hard time in understanding MODULE_DEVICE_TABLE(usb, id_table) usage) and in defining instance of usb_driver struct, see http://opensourceforu.efytimes.com/2011/11/usb-drivers-in-linux-2/.
what type of array initialization is this?
USB_DEVICE is a macro defined in include/linux/usb.h:
#define USB_DEVICE(vend, prod) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
.idVendor = (vend), \
.idProduct = (prod)
how this terminates?
C standard says:
The initialization shall occur in initializer list order, each
initializer provided for a particular subobject overriding any
previously listed initializer for the same subobject; all subobjects
that are not initialized explicitly shall be initialized implicitly
the same as objects that have static storage duration.
and:
If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate. If an object that has static
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;
if it is a union, the first named member is initialized
(recursively) according to these rules.
Thanks to this, id_table is defined as a pointer and not as an array inside usb_driver:
const struct usb_device_id *id_table;
Instead of passing an array size independently a function that uses id_table will increment pointer to id_table until one of its elements is NULL. See this short example that represents this technique:
#include <stdio.h>
#include <stdlib.h>
struct small
{
int a;
int b;
};
struct big
{
struct small *s;
};
struct small table[] =
{
{1, 1},
{2, 2},
{3, 3},
{}
};
int main(void)
{
struct big b = {
.s = table
};
const struct small *s;
/* traverse through table using pointer arithmetic */
for (s = b.s; s->a; s++)
{
printf("%d\n", s->a);
printf("%d\n", s->b);
}
exit(0);
}
I tried to initialize device id table in this way, but I am getting
errors as near initialization
I don't, are you sure you're not trying to redefine pen_table? What's an error message?
It's an array because it's how the data structure is defined and used.
You have n number of entries, and then a terminating entry (in this case, all zeros).
Wherever this array is used in initialization, it will start at the table symbol and consume entries until it hits the terminator, then stop. This way you don't need to communicate the number of entries as well.
This pattern facilitates late binding of configuration data with the library, and allows more compile time configuration, rather than run time configuration, and also requires fewer things to be in sync to operate correctly (so less chance for error).
Your second struct doesn't have a terminator, so the thing that's parsing the table just keeps on going and going and going until it crashes or gets errors.
I currently have some code in a function that looks like this:
static const int kFrameCountSample = 250;
static float * samples = (float *)calloc(kFrameCountSample, sizeof(float));
I like that the samples array is zeroed out exactly once with calloc().
I can also write the code so samples is allocated on the stack.
static const int kFrameCountSample = 250;
static float samples[kFrameCountSample];
but now samples is not initialized to zero values. How would I also initialize it at the time it is allocated?
For completeness (note: this is C99 NOT C++):
It's important to note that if you define and initialize a static array of length k to less than k - 1 values then the rest will be zero-filled. Hence:
static float samples[kFrameCountSample];
... is identical to:
static float samples[kFrameCountSample] = { 0 }; // Zero-fills.
... and will zero-fill samples. Moreover, if you do the following:
static float samples[kFrameCountSample] = { 1, 2, 3 }; // Zero-fills elements of position 3 ... 250.
... it will zero-fill the rest of the elements that are not assigned in the initialization of samples.
Remark:
Global variables are automatically zero-filled (and do not need to be initialized if this is the intent).
The standard for uninitialized static objects in section 6.7.8.10 of the C99 standard says:
"If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static 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;
if it is a union, the first named member is initialized (recursively) according to these rules."
The code that you've given:
static const int kFrameCountSample = 250;
static float samples[kFrameCountSample];
is not valid C. Objects with static storage duration can't have variably-modified type. On the other hand, this would be valid:
#define kFrameCountSample 250
static float samples[kFrameCountSample];
This is valid either at file scope or at function scope. In both cases the array samples has static storage duration, which means that it exists for the entire life of the program and is initialized only once, at program startup. The only difference is that if it's in a function, the scope of the name samples is restricted to the block in which it's declared. In neither case is it likely to be allocated on the stack.
The array samples here is zero-initialized - objects with static storage duration are never uninitialized. If you do not provide an explicit initializer, they are initialized to zero of the appropriate type.
If you do want an array stored on the stack - that is, created when the function containing the declaration is entered and destroyed when that function is exited, what C calls automatic storage duration - then you must declare it inside a function, omit the static keyword and add an explicit initializer:
float samples[kFrameCountSample] = { 0 };
(In this case kFrameCountSample does not need to be a macro, it can be a static const int if you want).
A single { 0 } is fine no matter what size the array is, because objects in C are never partially initialized - if you initialize any sub-object of an array or structure, the remaining sub-objects are initialized to zero of the appropriate type, just as with objects of static storage duration.
An array that only has some positions initialized to a value will have zeroes at the remaining positions.
static const int kFrameCOuntSample = 250;
static float samples[kFrameCOuntSample] = { 0 };
Should do the trick.
You can do memset to avoid any chances of something not being initlaized to zero.
static float samples[kFrameCountSample];
memset(samples,0,kFrameCountSample*sizeof(float));
http://man7.org/linux/man-pages/man3/memset.3.html
What it does is set a to every byte in samples. Meaning it's going to be initialized quickly to 0.
I've a question regarding the following code:
#include "all_needed.h"
static uint8_t array[2] = {0};
void main(void)
{
...
}
Is a (module) global array allowed to be initialized as above for having each member set to zero while being ANSI C conform?
I've got a problem in Code Composer 5 (MSP430 Project) where I had to change it into
static uint8_t array[2] = {0, 0};
for a correct initialization of the 2nd member of the array.
Yes, this is allowed, and should initialize the array to zero. C99, §6.7.8 p10:
If an object that has static 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;
— if it is a union, the first named member is initialized (recursively) according to these rules.
and p21:
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.
Report the bug to your compiler vendor.
Thanks for all your answers!
I've further investigated and found out that the Compiler is non-compliant as described in
http://www.ti.com/lit/pdf/SLAU157 in section B.5.1 "Initializing Static and Global Variables":
Appendix B: IAR 2.x/3.x/4.x to CCS C-Migration
B.5 Other Differences
B.5.1 Initializing Static and Global Variables
The ANSI/ISO C standard specifies that static and global (extern) variables without explicit initializations must be pre-initialized to 0 (before the program begins running). This task is typically performed when the program is loaded and is implemented in the IAR compiler:
/* IAR, global variable, initialized to 0 upon program start */
int Counter;
However, the TI CCS compiler does not pre-initialize these variables; therefore, it is up to the application to fulfill this requirement:
/* CCS, global variable, manually zero-initialized */
int Counter = 0;
The C standard says (6.7.8.21):
If there are fewer initializers in a brace-enclosed list than there are element of members of an aggregate [...], the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
In 6.2.5.21:
Array and structure types are collectively called aggregate types.
In other words, your code is OK.
static uint8_t array[2] = {0};
According to the C Standard, this will initialize both members of array to 0. If your compiler doesn't zero them, then it is in violation.
I work with PIC micros, so your mileage may vary...
There are different startup libraries I can link in. One will not initialize any RAM. One will clear all RAM to 0. Another with initialize the variables normally.
Take a look at the linker file and see what it is doing.
Are the members of a global or static structure in C guaranteed to be automatically initialized to zero, in the same way that uninitialized global or static variables are?
From the C99 standard 6.7.8/10 "Initialization":
If an object that has automatic
storage duration is not initialized
explicitly, its value is
indeterminate. If an object that has
static 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;
— if it is
a union, the first named member is
initialized (recursively) according to
these rules
Since globals and static structures have static storage duration, the answer is yes - they are zero initialized (pointers in the structure will be set to the NULL pointer value, which is usually zero bits, but strictly speaking doesn't need to be).
The C++ 2003 standard has a similar requirement (3.6.2 "Initialization of non-local objects"):
Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place.
Sometime after that zero-initialization takes place, constructors are called (if the object has a constructor) under the somewhat more complicated rules that govern the timing and ordering of those calls.
Local variables are not initialized.
struct foobar {
int x;
};
int main(void) {
struct foobar qux;
/* qux is uninitialized. It is a local variable */
return 0;
}
static local variables are initialized to 0 (zero)
struct foobar {
int x;
};
int main(void) {
static struct foobar qux;
/* qux is initialized (to 0). It is a static local variable */
return 0;
}
Global variables are initialized to 0 (zero)
struct foobar {
int x;
};
struct foobar qux;
/* qux is initialized (to 0). It is a global variable */
int main(void) {
return 0;
}
A struct is no different in this manner than a normal static C variable. The memory reserved for that struct is completely initialized to 0 if it's a static.
Yes, all global data is zeroed out, including the members of structures, classes and unions.
All data in global part of the program is set to zero.
The BSS segment also known as
Uninitialized data starts at the end
of the data segment and contains all
uninitialized global variables and
static variables that are initialized
to zero by default. For instance a
variable declared static int i; would
be contained in the BSS segment.
Bss segment.
I don't know why is it so hard to try it yourself btw.