Reputation: 3227
I am looking at the <linux/kfifo.h>
, specifically the DECLARE_KFIFO macro, and I can't figure out why use an union
.
#define DECLARE_KFIFO(name, size) \
union { \
struct kfifo name; \
unsigned char name##kfifo_buffer[size + sizeof(struct kfifo)]; \
}
My questions are as follows:
union
over here ? What design goal does that solve ? Is it for performance reasons ?How would you even access this anonymous union ? For example this does not work:
#include <stdio.h>
int main()
{
union {
int a;
float b;
};
a = 10;
}
main.c:18:5: error: ‘a’ undeclared (first use in this function)
a = 10;
^
Why declare something that cannot be used ?
Note: This code is for the 2.6.33 kernel. I know its old code, but the recent kernel 5.6.12 still uses a union in kfifo, only its a lot more complicated.
Upvotes: 1
Views: 485
Reputation: 66089
The comments to the macro explain almost everything:
/**
* DECLARE_KFIFO - macro to declare a kfifo and the associated buffer
* @name: name of the declared kfifo datatype
* @size: size of the fifo buffer. Must be a power of two.
*
* Note1: the macro can be used inside struct or union declaration
* Note2: the macro creates two objects:
* A kfifo object with the given name and a buffer for the kfifo
* object named name##kfifo_buffer
*/
This macro is used only as a (some other) structure's or union's field. With such usage the macro creates(allocates in the structure or in the union):
name
andSo, structure declaration like
struct my_struct {
int a;
char b;
DECLARE_KFIFO(my_fifo, 100);
};
gives similar effect as
struct my_struct {
int a;
char b;
// This field may be used for call kfifo functions
struct kfifo my_fifo;
// This field is never used directly.
// Pointer to this buffer is stored in the '.buffer' field of kfifo object.
unsigned char buffer_internal_to_kfifo_implementation[size];
};
It would be more natural for declaring two objects to use a anonymous structure of two fields instead of union:
#define DECLARE_KFIFO(name, size) \
struct { \
struct kfifo name; \
unsigned char name##kfifo_buffer[size]; \
}
It should be exactly anonymous for allow direct access to its name
field.
Compared to structure's implementation, actual implementation of DECLARE_KFIFO
via anonymous union gives the same "field" name
and allocates the same amount of bytes (of number size
) for its buffer:
union { \
struct kfifo name; \
unsigned char name##kfifo_buffer[size + sizeof(struct kfifo)]; \
}
It is difficult to say why they choose union
instead of struct
.
the recent kernel 5.6.12 still uses a union in kfifo, only its a lot more complicated.
Not quite true. The newer kernel versions uses union
for absolutely different purposes:
#define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \
union { \
struct __kfifo kfifo; \
datatype *type; \
const datatype *const_type; \
char (*rectype)[recsize]; \
ptrtype *ptr; \
ptrtype const *ptr_const; \
}
Here kfifo
is the only field which is accessed for write/read bytes of data. All other fields are declared just for extract their types using typeof()
operator.
So, __STRUCT_KFIFO_COMMON
is just a "clever" struct kfifo
declaration which knows types of data it contains.
Definition of DECLARE_KFIFO
macro
#define DECLARE_KFIFO(fifo, type, size) STRUCT_KFIFO(type, size) fifo
after expanding intermediate macros gives:
#define DECLARE_KFIFO(fifo, type, size) struct { \
__STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \
type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \
} fifo
So that time it is a field of the structure type with the given name. Similar to the old definition, this structure contain two fields:
struct kfifo
object (its "clever" version) andUpvotes: 1