What value have int fields in struct not initialized yet? - c

In the code:
...
#define MAXELEMNTS 100
struct book
{
int number;
char name[31];
char author[31];
int year;
char publisher[31];
};
struct book bkStruct[MAXELEMENTS];
...
Are the integer fields (number and year) initialized to 0 by default when the other char fields are initialized but not these two? Or do they have god-knows-what value? In my experience they do have value = 0, but I am not sure is this general rule so I must be sure!
Best regards,
Papo

In C there is no such thing as "partial initialization".
If a struct is initialized by specifying a value for a single member, all the other members are automagically initialized (to 0 of the proper kind).
struct book
{
int number;
char name[31];
char author[31];
int year;
char publisher[31];
};
struct book book1; // no initialization
struct book book2 = { .author = "pmg" }; // initialization of ALL of book2
struct book bkStruct1[MAXELEMENTS]; // uninitialized array
struct book bkStruct2[MAXELEMENTS] = {0}; // initialized array
// (every member of every element)
Note: some implementations may complain about missing braces on the perfectly legal array initialization. That is a problem with those implementations.

If you define an object with an initializer, it's initialized to the specified value. If you only specify values for some members, the others are initialized to zero (meaning 0 for integers (including characters), 0.0 for floating-point values, and NULL for pointers).
If you define an object without an initializer, all members are implicitly initialized to zero if the object has static storage duration, i.e., if it's defined outside any function or if it's defined with the static keyword.
An object defined inside a function without the static keyword has automatic storage duration. Such objects, if not explicitly initialized, start off with garbage values. (If you happen to see such objects seemingly initialized to zero, remember that zero can be just as much a garbage value as anything else.)
You asked:
Are the integer fields (number and year) initialized to 0 by default
when the other char fields are initialized but not these two?
but the code in your question doesn't initialize the char[] fields. See pmg's answer, which shows some good examples, but doesn't currently mention the static vs. automatic distinction.

to be on safe side you should intialize your varibales to 0 yourself depending upon compiler it might pick garbage value as well

Related

Structure of a book in C

I am new to C programming and in the development of this exercise I encountered this error that I cannot resolve:
Fields must have a constant size: 'variable length array in structure' extension will never be supported
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
int nChapters = 2;
typedef struct {
char title[50];
char author[50];
} Heading;
typedef struct {
char title[50];
int number_pages;
} Chapter;
typedef struct {
Heading heading;
Chapter chapters[nChapters]; //Fields must have a constant size: 'variable length array in structure' extension will never be supported
} Book;
printf("\n");
system("read -p 'Press enter to continue...' ");
printf("Hello, World!\n");
return 0;
}
If I replace chapters[nChapters] with an int like chapters[2], program run without problems. Thanks in advance!
In C you have to declare arrays using a fixed length, your nChapters variable is indeed, a variable. You can turn it into a constant variable by simply adding the const keyword:
const int nChapters = 2
You can use the preprocessor directive #define:
#define nChapters 2
The issue is that you are assuming that it is obvious
Chapter chapters[nChapters];
that value of nChapters is 2.
It works that way for a array which is not within a struct or a union.
This is supported by weird, non-standard, non-GCC (but accepted as an extension by GCC in C90 onwards), not recommended feature called as VLA or Variable Length Arrays. Using these, one can allocate a auto class array.
Referring to GNU/GCC documentation, section 6.20, It is trivial to note that,
The storage is allocated at the point of declaration and deallocated when the block scope containing the declaration exits.
C99 recommends a better way to deal with this requirement - by using flexible length array.
§6.7.2.1 Structure and union specifiers
¶18 As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply. However, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.
So, that would change your struct to:
typedef struct {
Heading heading;
Chapter chapters[];
} Book;
And then allocate the memory dynamically from heap - using malloc.
The size of the array member of the struct has to be a constant expression (skip "flexible member" case and GCC's VLA-in-struct extension).
In the C standard the only portable way to have a true named integer constant is using enums.
Just replace:
int nChapters = 2;
with this:
enum { nChapters = 2 };

Can the address of a variable with automatic storage duration be taken in its definition?

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.

Can someone please explain the difference between these two initiliazers?

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");
}
}

Usb device id table understanding

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.

Are the members of a global structure initialized to zero by default in C?

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.

Resources