I am new to the Linux kernel. I am reading the file ioctl.h
, there I encountered a macro
_IOC_TYPECHECK(t)
, which looks like this:
#define _IOC_TYPECHECK(t) \
((sizeof(t) == sizeof(t[1]) && \
sizeof(t) < (1 << _IOC_SIZEBITS)) ? \
sizeof(t) : __invalid_size_argument_for_IOC)
Can you explain me this code? In this code, what does sizeof(t[1])
mean?
sizeof(* int) returns the size of the address value, that is, a byte. address that points to a byte position in memory that stores an int. value. The address values are typically 4 byte integers themselves on a. 32 bit system, so sizeof(*int) would return 4.
sizeof(int) > (unsigned int)-1 is false, because (unsigned int)-1 is a very large number on most implementations (equal to UINT_MAX, or the largest number which fits in an unsigned int ).
The sizeof operator yields the size in bytes of the operand, which can be an expression or the parenthesized name of a type.
On a 32-bit Machine, sizeof(int*) will return a value 4 because the address value of memory location on a 32-bit machine is 4-byte integers. Similarly, on a 64-bit machine it will return a value of 8 as on a 64-bit machine the address of a memory location are 8-byte integers.
This is used to check the validity of the third parameter to the _IOR
/_IOW
/_IOWR
macros, which is supposed to be a type. It checks that the parameter is actually a type (and not a variable or a number), and causes a compiler or linker error otherwise.
If t
is a type, then t[1]
is the type "an array of 1 t
". This type has the same size as t
, and therefore sizeof(t) == sizeof(t[1])
is true.
If t
is a number, sizeof(t)
will fail to compile.
If t
is a simple (non-array) variable, then t[1]
will cause a compiler error.
If t
is an array variable, sizeof(t) == sizeof(t[1])
will be false, and a linker error will be caused (because __invalid_size_argument_for_IOC
is not defined).
The expression sizeof(t) < (1 << _IOC_SIZEBITS)
checks that the size of the type t
does not exceed the maximum allowed for ioctl
, and causes the same linker error otherwise.
There are still some invalid cases which will not be caught by this macro - for example, when t
is a pointer to a pointer.
It means the same as all other uses of sizeof
. It computes the size of the expression.
In this particular case, I suspect that the check is intended to ensure some property of t
(which should be a type name, not a variable) which I don't know from the context ... Perhaps that it's possible to treat it as a pointer (needed for the array indexing) which would rule out some types. The comment next to the macro says /* provoke compile error for invalid uses of size argument */
which seems to support this theory.
Note that sizeof
is an operator, not a function. The parenthesis are not needed, except when you want to compute the size of a type directly, and then they're part of the expression (it's a cast expression). So this could be written sizeof t == sizeof t[1] && ...
, or maybe (sizeof t == sizeof t[1])
for clarity.
This is a very good style to use, since it "locks" the size being computed to the proper array, instead of repeating the type of t
. So, if the type were to change, the expression would automatically adapt and still compute the right thing.
Many C programmers seem to prefer having parenthesis around the argument to sizeof
in all cases, for some reason.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With