2. 注释

单行注释应采用/*␣comment␣*/的形式,用空格把界定符和文字分开。多行注释最常见的是这种形式:

  1. /*
  2. ␣*␣Multi-line
  3. ␣*␣comment
  4. ␣*/

也有更花哨的形式:

  1. /*************\
  2. * Multi-line *
  3. * comment *
  4. \*************/

使用注释的场合主要有以下几种。

1、整个源文件的顶部注释。说明此模块的相关信息,例如文件名、作者和版本历史等,顶头写不缩进。例如内核源代码目录下的kernel/sched.c文件的开头:

  1. /*
  2. * kernel/sched.c
  3. *
  4. * Kernel scheduler and related syscalls
  5. *
  6. * Copyright (C) 1991-2002 Linus Torvalds
  7. *
  8. * 1996-12-23 Modified by Dave Grothe to fix bugs in semaphores and
  9. * make semaphores SMP safe
  10. * 1998-11-19 Implemented schedule_timeout() and related stuff
  11. * by Andrea Arcangeli
  12. * 2002-01-04 New ultra-scalable O(1) scheduler by Ingo Molnar:
  13. * hybrid priority-list and round-robin design with
  14. * an array-switch method of distributing timeslices
  15. * and per-CPU runqueues. Cleanups and useful suggestions
  16. * by Davide Libenzi, preemptible kernel bits by Robert Love.
  17. * 2003-09-03 Interactivity tuning by Con Kolivas.
  18. * 2004-04-02 Scheduler domains code by Nick Piggin
  19. */

2、函数注释。说明此函数的功能、参数、返回值、错误码等,写在函数定义上侧,和此函数定义之间不留空行,顶头写不缩进。

3、相对独立的语句组注释。对这一组语句做特别说明,写在语句组上侧,和此语句组之间不留空行,与当前语句组的缩进一致。

4、代码行右侧的简短注释。对当前代码行做特别说明,一般为单行注释,和代码之间至少用一个空格隔开,一个源文件中所有的右侧注释最好能上下对齐。尽管例 2.1 “带更多注释的Hello World”讲过注释可以穿插在一行代码中间,但不建议这么写。内核源代码目录下的lib/radix-tree.c文件中的一个函数包含了上述三种注释:

  1. /**
  2. * radix_tree_insert - insert into a radix tree
  3. * @root: radix tree root
  4. * @index: index key
  5. * @item: item to insert
  6. *
  7. * Insert an item into the radix tree at position @index.
  8. */
  9. int radix_tree_insert(struct radix_tree_root *root,
  10. unsigned long index, void *item)
  11. {
  12. struct radix_tree_node *node = NULL, *slot;
  13. unsigned int height, shift;
  14. int offset;
  15. int error;
  16.  
  17. /* Make sure the tree is high enough. */
  18. if ((!index && !root->rnode) ||
  19. index > radix_tree_maxindex(root->height)) {
  20. error = radix_tree_extend(root, index);
  21. if (error)
  22. return error;
  23. }
  24.  
  25. slot = root->rnode;
  26. height = root->height;
  27. shift = (height-1) * RADIX_TREE_MAP_SHIFT;
  28.  
  29. offset = 0; /* uninitialised var warning */
  30. do {
  31. if (slot == NULL) {
  32. /* Have to add a child node. */
  33. if (!(slot = radix_tree_node_alloc(root)))
  34. return -ENOMEM;
  35. if (node) {
  36. node->slots[offset] = slot;
  37. node->count++;
  38. } else
  39. root->rnode = slot;
  40. }
  41.  
  42. /* Go a level down */
  43. offset = (index >> shift) & RADIX_TREE_MAP_MASK;
  44. node = slot;
  45. slot = node->slots[offset];
  46. shift -= RADIX_TREE_MAP_SHIFT;
  47. height--;
  48. } while (height > 0);
  49.  
  50. if (slot != NULL)
  51. return -EEXIST;
  52.  
  53. BUG_ON(!node);
  54. node->count++;
  55. node->slots[offset] = item;
  56. BUG_ON(tag_get(node, 0, offset));
  57. BUG_ON(tag_get(node, 1, offset));
  58.  
  59. return 0;
  60. }

[CodingStyle]中特别指出,函数内的注释要尽可能少用。写注释主要是为了说明你的代码“能做什么”(比如函数接口定义),而不是为了说明“怎样做”,只要代码写得足够清晰,“怎样做”是一目了然的,如果你需要用注释才能解释清楚,那就表示你的代码可读性很差,除非是特别需要提醒注意的地方才使用函数内注释。

5、复杂的结构体定义比函数更需要注释。例如内核源代码目录下的kernel/sched.c文件中定义了这样一个结构体:

  1. /*
  2. * This is the main, per-CPU runqueue data structure.
  3. *
  4. * Locking rule: those places that want to lock multiple runqueues
  5. * (such as the load balancing or the thread migration code), lock
  6. * acquire operations must be ordered by ascending &runqueue.
  7. */
  8. struct runqueue {
  9. spinlock_t lock;
  10.  
  11. /*
  12. * nr_running and cpu_load should be in the same cacheline because
  13. * remote CPUs use both these fields when doing load calculation.
  14. */
  15. unsigned long nr_running;
  16. #ifdef CONFIG_SMP
  17. unsigned long cpu_load[3];
  18. #endif
  19. unsigned long long nr_switches;
  20.  
  21. /*
  22. * This is part of a global counter where only the total sum
  23. * over all CPUs matters. A task can increase this counter on
  24. * one CPU and if it got migrated afterwards it may decrease
  25. * it on another CPU. Always updated under the runqueue lock:
  26. */
  27. unsigned long nr_uninterruptible;
  28.  
  29. unsigned long expired_timestamp;
  30. unsigned long long timestamp_last_tick;
  31. task_t *curr, *idle;
  32. struct mm_struct *prev_mm;
  33. prio_array_t *active, *expired, arrays[2];
  34. int best_expired_prio;
  35. atomic_t nr_iowait;
  36.  
  37. #ifdef CONFIG_SMP
  38. struct sched_domain *sd;
  39.  
  40. /* For active balancing */
  41. int active_balance;
  42. int push_cpu;
  43.  
  44. task_t *migration_thread;
  45. struct list_head migration_queue;
  46. int cpu;
  47. #endif
  48.  
  49. #ifdef CONFIG_SCHEDSTATS
  50. /* latency stats */
  51. struct sched_info rq_sched_info;
  52.  
  53. /* sys_sched_yield() stats */
  54. unsigned long yld_exp_empty;
  55. unsigned long yld_act_empty;
  56. unsigned long yld_both_empty;
  57. unsigned long yld_cnt;
  58.  
  59. /* schedule() stats */
  60. unsigned long sched_switch;
  61. unsigned long sched_cnt;
  62. unsigned long sched_goidle;
  63.  
  64. /* try_to_wake_up() stats */
  65. unsigned long ttwu_cnt;
  66. unsigned long ttwu_local;
  67. #endif
  68. };

6、复杂的宏定义和变量声明也需要注释。例如内核源代码目录下的include/linux/jiffies.h文件中的定义:

  1. /* TICK_USEC_TO_NSEC is the time between ticks in nsec assuming real ACTHZ and */
  2. /* a value TUSEC for TICK_USEC (can be set bij adjtimex) */
  3. #define TICK_USEC_TO_NSEC(TUSEC) (SH_DIV (TUSEC * USER_HZ * 1000, ACTHZ, 8))
  4.  
  5. /* some arch's have a small-data section that can be accessed register-relative
  6. * but that can only take up to, say, 4-byte variables. jiffies being part of
  7. * an 8-byte variable may not be correctly accessed unless we force the issue
  8. */
  9. #define __jiffy_data __attribute__((section(".data")))
  10.  
  11. /*
  12. * The 64-bit value is not volatile - you MUST NOT read it
  13. * without sampling the sequence number in xtime_lock.
  14. * get_jiffies_64() will do this for you as appropriate.
  15. */
  16. extern u64 __jiffy_data jiffies_64;
  17. extern unsigned long volatile __jiffy_data jiffies;