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.
Related
hope everyone is doing great!
I was trying to implement some lib in embbeded enviroment, where i need to use const pointers.
Here is the code i was trying to do:
#include <stdio.h>
int a = 10;
typedef struct {
void * const payload;
int size;
} msg;
typedef struct {
void * const payload2encode;
int size2encode;
} encode_msg;
msg message[1] = {
{
/* payload */ &a,
0
}
};
encode_msg encoded_message = {
/* payload */ message[0].payload,
0
};
int main(void){
return 0;
}
but i'm getting the following error:
main.c:23:19: error: initializer element is not constant 23 |
/* payload */ message[0].payload,
If I change 'message[0].payload' to '&a' the code runs fine. I don't get why this is happening :(. Anyone know why?
Best reggards!
There are a lot of misconceptions here.
First of all, why do you need a "constant pointer"? This message here:
error: initializer element is not constant
Does not mean "the compiler wants a constant pointer", but rather "I want a a compile-time constant such as an integer constant expression". This has nothing to do with const at all in C (C++ is another story), but this:
A variable with static storage duration, like one declared at file scope outside any function, must be initialized with a constant expression. Such as an integer constant expression or in case of pointers the address of another variable. But it cannot be initialized to the value of a different variable. Simple example:
int a = 0;
int b = a; // error: initializer element is not constant
That's just how the language works. You could initialize a pointer to an address however, since address constants are constant expressions. That's why /* payload */ &a, works.
Next misconception: there is nothing called "constant pointer". There are:
pointers to read-only data, const type* name.
read-only pointers to read/write data: type* const name.
read-only pointers to read-only data: const type* const name.
For some reason you picked the second of these options (took a gamble?). It has limited uses, but one valid use of it is to declare read-only pointer variables in ROM on embedded systems with true ROM like flash.
Also we usually don't want to use qualifiers like const inside a struct on an individual member if we can avoid it. Because then the struct variable itself ends up with different qualifiers than it's members. Normally we want the whole struct to be const or nothing in the struct at all. In embedded systems we also need to consider if we want it to be stored in RAM or flash.
Regarding void*, they are not very suitable to use for any purpose in an embedded system. uint8_t* boiling down to a character pointer is much more useful, since it can be used to access any other type byte by byte. Whereas a void* has to be converted to another type before we can do anything meaningful with it. Type-generic programming in embedded systems is also a bad idea most of the time, since such systems should behave deterministically.
encoded_message has static storage duration (because it's declared outside any function) and so must be initialized with a constant expression, and message[0].payload isn't (it's a const variable, but not a constant expression).
You can either declare encoded_message in a function (main, for instance), or, if your compiler supports it, make message const as well.
See also : Error "initializer element is not constant" when trying to initialize variable with const
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 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");
}
}
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
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
.ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};
This declaration uses the standard C
tagged structure initialization
syntax.
Can someone elaborate?
When you use aggregate initializers (initializers in {}) in the "traditional" ANSI C language (C89/90), you have to supply an individual initializer for each structure member in order, beginning with the first. For example
struct S { int a, b, c, d; };
struct S s = { 1, 2, 3, 4 };
/* 1 for `s.a`, 2 for `s.b` and so on... */
You are not required to specify initializers for all members, i.e. you can stop at any time (remaining members will be zero-initialized).
If for some reason you only cared to explicitly initialize the third member of the structure, you had to supply "dummy" explicit initializers for the first and the second members (just to get to the desired third)
/* We only care to explicitly initialize `s.c` */
struct S s = { 0, 0, 3 };
/* but we have to explicitly initialize `s.a` and `s.b` as well */
or abandon specific initialization entirely (likely replacing it with generic = { 0 }) and use a subsequent assignment to specific members
struct S s = { 0 };
s.c = 3;
One notable benefit of this assignment-based approach is that it is independent from the position of member c in the declaration of struct S.
The new specification of C language (C99) allows you to use "tagged" initializers by supplying the desired member name within the {}
struct S s = { .c = 3 };
That way you only explicitly initialize the desired member(s) (and have the compiler to zero-initialize the rest). This not only saves you some typing but also makes the aggregate initializers independent from the order in which the members are specified in the struct type declaration.
Aggregate initializers, as you probably know, can be used with arrays, too. And C99 supports "tagged" initialization with arrays as well. How the "tags" look in case of an array is illustrated by the following example
int a[10] = { [5] = 3 };
/* `a[5]` is initialized with 3, the rest of `a` is zero-initialized */
It is worth noting one more time that C language continues to stick to the "all or nothing" approach to aggregate initialization: if you specify an explicit initializer for just one (or some) members of a struct or an array, the whole aggregate gets initialized, and the members without explicit initializers get zero-initialized.
You're using the names of the members of the structure to initialise the structure. i.e. each member initialisation is "tagged" with that member's name.
Another benefit worth mention regarding this type of initialization is that it allows the reordering of structure members, which in some cases, can make performance improvements by, for instance ,placing pointers to frequently accessed members in the same hardware cache line.