本篇英文链接https://www.kernel.org/doc/Documentation/process/coding-style.rst
对结构体和指针使用typedef是一种错误的用法。当你在源码中看到下面的代码,你能判断出它的含义吗?
.. code-block:: c
vps_t a;
相反,如果它这样表述
.. code-block:: c
struct virtual_container *a;
你可以很轻松判断出指针a的类型。
很多人觉得typedef增强了程序的可读性。事实并不是这样,它只对以下几种情况有好处:
- 彻底屏蔽对象。
举个例子: 诸如pte_t
. 将那些只能通过正确的函数访问的对象屏蔽起来。
.. 注意::
像是“不透明性”和“访问函数”这样的东西,他们本身就不是很恰当。
对于它们存在的意义,就跟pte_t
一样,我们也不知道,因为根本没有任何可以查阅的资料。 去除整数类型,通过抽象来避免一些困惑,比如纠结于一个数据到底是int类型还是long类型。
使用typedef来定义u8/u16/u32完全没有问题。.. 注意::
再次强调,除非你有充分的理由来进行这样的定义。如果有个元素是
unsigned long
类型,那么再使用typedef unsigned long myflags_t;
就没意义了。
但如果你确实清楚,由于某种原因,在一些情况下它是unsigned int
, 但是在其它情况下又变成unsigned long
, 那么你大可放心使用typedef来解决这个问题。当你正确地创建少量地新类型来进行类型检查。
在某些特殊情况下,新的类型独立于C99标准中所规定地类型。
虽然你是需要花费很少的精力和时间就能适应诸如uint32_t
这样的标准类型,但是一些人还是反对这种写法的使用。
因此,Linux指定了u8/u16/u32/u64
这些类型,它们与标准类型完全等价——但是并不强制要求你的新代码中使用它们。
当一份代码已经使用了某种类型表示方式的时候,你需要继续遵循它所选择的表述方式。- 类型可以安全地应用于用户空间。
当结构体在用户空间中可见的时候,我们不能使用上面讲到的u32
。因此,我们在结构体中使用类似于__u32
的类型。
可能还有一些其它情况,但基本上规定:除非你能够确切地匹配上面几种情况的某一种,否则永远不要使用typedef。
一般来说,一个指针或者结构体中如果包含能够被直接访问的元素,那么绝对不能使用typedef。