Linux内核编码风格(编程代码风格推荐)
谈谈为 Linux 内核写驱动的编码规范
谈谈为 Linux 内核写驱动的编码规范最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离Linux内核的coding style要求还是差很多。
当初自己对内核文档里的CodingStyle一文只是粗略的浏览,真正写代码的时候在很多细节上会照顾不周。
不过,在不遵守规则的程序员队伍里,我并不是孤独的。
如果去看drivers/staging下的代码,就会发现很多驱动程序都没有严格遵守内核的coding style,而且在很多驱动程序的TODO文件里,都会把"checkpatch.pl fixes"作为自己的目标之一(checkpatch.pl是用来检查代码是否符合coding style的脚本)。
不可否认,coding style是仁者见仁、智者见智的事情。
比如Microsoft所推崇的匈牙利命名法,在Linus看来就是及其脑残(brain damaged)的做法。
也许您并不赞成Linus制定的coding style,但在提交内核驱动这件事上,最好还是以大局为重。
对于这么一个庞大的集市式的开发来说,随意书写代码必将带来严重的可维护性的灾难。
(题图来自:mota.ru)一些辅助工具当代码量达到一定程度时,手动去检查和修改coding style是非常繁琐的工作,幸好,我们还有一些工具可以使用。
scripts/checkpatch.pl这是一个检查代码是否符合内核编码规范的的脚本。
顾名思义,checkpatch是用来检查patch的,默认的调用也确实如此。
如果用来检查原文件,需要加上“-f”的选项。
我们来看一段无聊的代码(文件名为print_msg.c):1.void print_msg(int a)2.{3. switch (a) {4. case 1:5. printf("a == 1\n");6. break;7.8. case 2:9. printf("a == 2\n");10. break;11. }12.}这段代码的coding style是否有问题呢?用checkpatch.pl来检查一下:1.scripts/checkpatch.pl -f print_msg.c检查的结果是:1.ERROR: switch and case should be at the same indent2.#3: FILE: switch.c:3:3.+ switch (a) {4.+ case 1:5.[...]6.+ case 2:7.8.total: 1 errors, 0 warnings, 12 lines checked9.10.switch.c has style problems, please review. If any of theseerrors11.are false positives report them to the maintainer, see12.CHECKPATCH in MAINTAINERS.在Linux内核的coding style里,switch和case要求有相同的缩进。
LINUX内核模块编程指南
LINUX内核模块编程指南Linux内核模块编程是一种在Linux操作系统中向内核添加新功能的方法。
内核模块是一段特殊的代码,可以被编译并加载到内核中,从而实现对操作系统底层的修改和扩展。
下面将介绍一些关键的步骤和注意事项,以帮助初学者入门Linux内核模块编程。
首先,要编写一个内核模块,需要有合适的开发环境。
一般来说,需要一台运行Linux的计算机,并安装有相应的开发工具链(如GCC编译器)和Linux内核源代码。
编写内核模块的第一步是定义模块的入口函数。
在C语言中,入口函数的原型通常是`int init_module(void)`。
在该函数中,可以注册一些回调函数来处理特定的事件,或者进行其他必要的初始化工作。
接下来,可以添加自定义的函数和数据结构,以实现模块的功能。
这些函数和数据结构可以被其他模块或内核中的其他代码调用和使用。
由于内核是一个复杂的系统,因此在编写内核模块时需要特别关注数据的正确性和同步性。
在编写模块的过程中,还需要了解一些内核编程的特殊机制,如内核的锁机制、中断处理和内存管理等。
对这些内容的学习需要一定的时间和精力,但是它们是实现高性能和高可靠性内核模块的关键。
完成模块的编写后,需要对其进行编译和加载。
一般来说,可以使用Makefile来编译模块,并且可以使用insmod命令来加载模块。
加载模块时,内核将会调用模块的入口函数,从而完成初始化工作。
在模块编写和调试的过程中,需要注意一些常见的问题。
例如,内核模块应该遵守内核的编程规范和风格,避免对内核进行不必要的修改或侵入。
此外,要时刻注意内存管理和锁机制,以防止出现内存泄漏或并发访问的问题。
最后,需要强调的是,Linux内核模块编程是一项复杂而底层的技术。
对于初学者来说,学习和掌握这些知识需要一定的时间和耐心,并且需要有一定的计算机基础和编程经验。
但是,一旦熟练掌握了这些技术,就能够更加深入地了解和使用Linux操作系统,并且为其添加新的功能。
LINUX编程风格
Linux编程风格0.1一、GNU风格1.函数返回类型说明和函数名分两行放置,函数起始字符和函数开头左花括号放到最左边,例如:static char *main (argc, argv)int argc;char *argv[];{......}或者是用标准C:static char *main (int argc, char *argv[]){......}如果参数太长不能放到一行,请在每行参数开头处对齐:intnet_connect (struct sockaddr_in *cs, char *server, unsigned short int port,char *sourceip, unsigned short int sourceport, int sec) 对于函数体,我们应该按照如何方式排版:在左括号之前、逗号之后,以及运算符号前后添加空格使程序便于阅读,例如:if (x < foo (y, z))haha = bar[4] + 5;else{while (z){haha += foo (z, z);z--;}return ++x + bar ();}当一个表达式需要分成多行书写的时候,应该在操作符之前分割。
例如:if (foo_this_is_long && bar > win (x, y, z)&& remaining_condition)2. 尽量不要让两个不同优先级的操作符出现在相同的对齐方式中,应该附加额外的括号使得代码缩进可以表示出嵌套。
例如:错误的对齐:mode = (inmode[j] == VOIDmode|| GET_MODE_SIZE (outmode[j]) > GET_MODE_SIZE (inmode[j])? outmode[j] : inmode[j];正确的对齐:mode = ((inmode[j] == VOIDmode|| (GET_MODE_SIZE (outmode[j]) > GET_MODE_SIZE (inmode[j]))) ? outmode[j] : inmode[j];3. 按照如下方式排版do-while语句:do{a = foo (a);}while (a > 0);4. 每个程序都应该以一段简短的说明其功能的注释开头。
linux 的编码格式
linux 的编码格式**Linux 编码格式简介**在Linux 系统中,编码格式起着至关重要的作用。
它是一种将字符转换为二进制的方式,以便在计算机内部进行存储和传输。
了解Linux 编码格式对于更好地使用这个强大的操作系统至关重要。
**Linux 常用编码格式对比**Linux 系统中存在多种编码格式,其中最常用的有ASCII、UTF-8、GBK 等。
1.ASCII:这是一种最基本的编码格式,主要应用于英文和数字。
然而,它在处理中文等复杂字符时存在局限性。
2.UTF-8:这是一种广泛应用于Linux 的编码格式,它可以表示几乎所有的Unicode 字符。
UTF-8 具有良好的兼容性和跨平台性,是目前Linux 系统中最为推荐的编码格式。
3.GBK:这是一种针对中文设计的编码格式,适用于简体中文环境。
在Linux 系统中,GBK 编码可以满足大部分中文文本的处理需求。
**如何选择合适的编码格式**在选择编码格式时,需要考虑以下几个方面:1.目标用户:根据您的读者群体,选择他们熟悉的编码格式。
例如,面向国内用户,可以选择GBK 编码;面向国际用户,可以选择UTF-8 编码。
2.文件兼容性:确保所选编码格式与其他操作系统和软件的兼容性。
例如,使用UTF-8 编码可以确保在各种操作系统和设备上都能正常显示文本。
3.存储空间:较小的编码格式如ASCII 和GBK 占用存储空间较少,但处理字符范围有限;UTF-8 编码虽然兼容性较好,但占用存储空间相对较大。
4.文本处理需求:根据您的文本处理需求,选择合适的编码格式。
例如,如果您需要处理大量特殊字符或Unicode 字符,可以选择UTF-8 编码。
**编码格式在Linux 中的应用场景**编码格式在Linux 系统中有着广泛的应用场景,如:1.文本编辑器:不同的编码格式可以在文本编辑器中显示和编辑不同类型的文本。
2.编程语言:编程语言中的变量名、注释和字符串常使用编码格式进行存储和处理。
Linux底层驱动开发的最佳实践让你的代码更优雅
Linux底层驱动开发的最佳实践让你的代码更优雅在Linux系统中,底层驱动扮演着连接硬件设备与操作系统的重要角色。
良好的驱动开发实践不仅能够确保系统的稳定性和性能,还能提高代码的可读性和可维护性。
本文将介绍一些Linux底层驱动开发的最佳实践,帮助你编写更优雅的驱动代码。
1. 遵循Linux内核开发规范Linux内核有一套自己的开发规范,严格遵循这些规范能够确保你的驱动代码与内核的其他模块相协调。
比如,驱动应该使用适当的内核API来访问硬件,而不是直接与硬件进行交互。
此外,在注册驱动时,应该明确指定驱动支持的设备ID,以避免与其他驱动产生冲突。
2. 使用合适的数据结构在编写驱动代码时,选择合适的数据结构对于代码的可读性和可维护性非常重要。
Linux内核提供了许多常用的数据结构,如链表、哈希表和位图等,驱动开发者可以根据实际需求选择合适的数据结构来组织和管理设备数据。
3. 使用适当的设备驱动模型Linux内核提供了多种设备驱动模型,如Platform Driver、Character Driver和Network Driver等。
选择合适的设备驱动模型有助于简化驱动开发流程,并提高代码的可维护性。
例如,如果你的驱动只需要与特定硬件平台进行通信,那么Platform Driver模型可能是最合适的选择。
4. 优化中断处理中断处理是驱动开发中一个关键的环节。
合理处理中断可以提高系统的响应性能。
在编写中断处理程序时,应该尽量减少对共享资源的访问,使用适当的同步机制来保护共享资源的访问。
5. 调试和错误处理在驱动开发过程中,合理的调试和错误处理机制是非常重要的。
你可以使用调试工具和技术来跟踪代码执行流程、打印调试信息和监测性能瓶颈。
此外,你还应该为驱动添加适当的错误处理代码,以应对意外情况和异常情况,提高系统的稳定性。
6. 编写适当的文档为你的驱动代码编写适当的文档是一种良好的开发实践。
文档应该包括驱动的功能、接口、使用示例和注意事项等信息,以方便其他开发者使用和理解你的代码。
linux操作系统内核版表达方式
Linux操作系统内核源代码的表达方式Linux操作系统内核源代码的表达方式是指内核代码中所使用的语法和结构。
它决定了内核代码的可读性、可维护性和可移植性。
内核源代码的表达方式主要包括以下几个方面:语法:Linux内核源代码使用C语言编写。
C语言是一种广泛使用的通用编程语言,具有丰富的库和工具支持,并且很容易移植到不同的平台上。
结构:Linux内核源代码由许多相互关联的文件组成,这些文件包含了内核的各种功能和模块。
内核源代码的结构通常是分层的,每一层都包含了不同的功能。
命名约定:Linux内核源代码使用了严格的命名约定,这使得内核代码更容易阅读和维护。
例如,内核中的函数通常以“sys_”或“do_”开头,而结构体通常以“struct_”开头。
注释:Linux内核源代码中包含了大量的注释,这些注释解释了代码的功能和用法。
注释对于理解内核代码非常有用,尤其是对于新内核开发者来说。
Linux内核源代码的表达方式的特点Linux内核源代码的表达方式具有以下几个特点:简洁:Linux内核源代码非常简洁,代码中没有多余的注释和代码段。
这种简洁性使得内核代码更容易阅读和维护。
模块化:Linux内核源代码是模块化的,内核中的各个模块可以独立编译和加载。
这种模块化设计使得内核更容易扩展和维护。
可移植性:Linux内核源代码具有很强的可移植性,它可以移植到不同的硬件平台上。
这种可移植性使得Linux内核成为世界上最受欢迎的操作系统之一。
Linux内核源代码的表达方式的优点Linux内核源代码的表达方式具有以下几个优点:可读性:Linux内核源代码非常可读,代码中的注释和命名约定使得内核代码很容易理解。
这种可读性对于内核开发者来说非常重要,它可以帮助开发者快速理解和修改内核代码。
可维护性:Linux内核源代码也非常可维护,代码中的模块化设计使得内核更容易扩展和维护。
这种可维护性对于内核的长期发展非常重要,它可以确保内核能够不断更新和改进。
Linux内核编码风格
Linux内核编码风格 像其他⼤型软件⼀样,Linux制订了⼀套编码风格,对代码的格式、风格和布局做出了规定。
我写这篇的⽬的也就是希望⼤家能够从中借鉴,有利于⼤家提⾼编程效率。
像Linux内核这样⼤型软件中,涉及许许多多的开发者,故它的编码风格也很有参考价值。
1、左括号紧跟在语句的最后,与语句在相同的⼀⾏。
⽽右括号要另起⼀⾏,作为该⾏的第⼀个字符。
2、如果接下来的部分是相同语句的⼀部分,那么右括号就不单独占⼀⾏。
3、还有 4、函数采⽤以下的书写⽅式: 5、最后不需要⼀定使⽤括号的语句可以忽略它: 要尽可能地保证代码长度不超过80个字符,如果代码⾏超过80应该折到下⼀⾏。
将参数分⾏输⼊,在开头简单地加⼊两个标准tab: 名称中不允许使⽤混合的⼤⼩写字符。
局部变量如果能够清楚地表明它的⽤途,那么选取idx甚⾄是i这样的名称都是可⾏的。
⽽像theLoopIndex这样冗长反复的名字不在接受之列。
——匈⽛利命名法(在变量名称中加⼊变量的类别)危害极⼤。
函数 根据经验函数的代码长度不应该超过两屏,局部变量不应该超过⼗个。
1、⼀个函数应该功能单⼀并且实现精准。
2、将⼀个函数分解成⼀些更短⼩的函数的组合不会带来危害。
——如果你担⼼函数调⽤导致的开销,可以使⽤inline关键字。
⼀般情况下,注释的⽬的是描述你的代码要做什么和为什么要做,⽽不是具体通过什么⽅式实现的。
怎么实现应该由代码本⾝展现。
注释不应该包含谁写了那个函数,修改⽇期和其他那些琐碎⽽⽆实际意义的内容。
这些信息应该集中在⽂件最开头地⽅。
内核中⼀条注释看起来如下: 重要信息常常以“XXX:”开头,⽽bug通常以“FIXME"开头,就像:总结 希望这篇博客对⼤家有所帮助!更详尽的内容,请看"Linux 内核代码规范原⽂"Linus 内部代码规范原⽂1 Linux kernel coding style23 This is a short document describing the preferred coding style for the4 linux kernel. Coding style is very personal, and I won't _force_ my5 views on anybody, but this is what goes for anything that I have to be6 able to maintain, and I'd prefer it for most other things too. Please7 at least consider the points made here.89 First off, I'd suggest printing out a copy of the GNU coding standards,10 and NOT read it. Burn them, it's a great symbolic gesture.1112 Anyway, here goes:131415 Chapter 1: Indentation1617 Tabs are 8 characters, and thus indentations are also 8 characters.18 There are heretic movements that try to make indentations 4 (or even 2!)19 characters deep, and that is akin to trying to define the value of PI to20 be 3.2122 Rationale: The whole idea behind indentation is to clearly define where23 a block of control starts and ends. Especially when you've been looking24 at your screen for20 straight hours, you'll find it a lot easier to see25 how the indentation works if you have large indentations.2627 Now, some people will claim that having 8-character indentations makes28 the code move too far to the right, and makes it hard to read on a2980-character terminal screen. The answer to that is that if you need30 more than 3 levels of indentation, you're screwed anyway, and should fix31 your program.3233 In short, 8-char indents make things easier to read, and have the added34 benefit of warning you when you're nesting your functions too deep.35 Heed that warning.3637 The preferred way to ease multiple indentation levels in a switch statement is38 to align the "switch" and its subordinate "case" labels in the same column39 instead of "double-indenting" the "case" labels. E.g.:4041switch (suffix) {42case'G':43case'g':44 mem <<= 30;45break;46case'M':47case'm':48 mem <<= 20;49break;51case'k':52 mem <<= 10;53/* fall through */54default:55break;56 }575859 Don't put multiple statements on a single line unless you have60 something to hide:6162if (condition) do_this;63 do_something_everytime;6465 Don't put multiple assignments on a single line either. Kernel coding style66is super simple. Avoid tricky expressions.6768 Outside of comments, documentation and except in Kconfig, spaces are never69 used for indentation, and the above example is deliberately broken.7071 Get a decent editor and don't leave whitespace at the end of lines.727374 Chapter 2: Breaking long lines and strings7576 Coding style is all about readability and maintainability using commonly77 available tools.7879 The limit on the length of lines is80 columns and this is a strongly80 preferred limit.8182 Statements longer than 80 columns will be broken into sensible chunks, unless83 exceeding 80 columns significantly increases readability and does not hide84 information. Descendants are always substantially shorter than the parent and85 are placed substantially to the right. The same applies to function headers86 with a long argument list. However, never break user-visible strings such as87 printk messages, because that breaks the ability to grep for them.888990 Chapter 3: Placing Braces and Spaces9192 The other issue that always comes up in C styling is the placement of93 braces. Unlike the indent size, there are few technical reasons to94 choose one placement strategy over the other, but the preferred way, as95 shown to us by the prophets Kernighan and Ritchie, is to put the opening96 brace last on the line, and put the closing brace first, thusly:9798if (x is true) {99 we do y100 }101102 This applies to all non-function statement blocks (if, switch, for,103while, do). E.g.:104105switch (action) {106case KOBJ_ADD:107return"add";108case KOBJ_REMOVE:109return"remove";110case KOBJ_CHANGE:111return"change";112default:113return NULL;114 }115116 However, there is one special case, namely functions: they have the117 opening brace at the beginning of the next line, thus:118119int function(int x)120 {121 body of function122 }123124 Heretic people all over the world have claimed that this inconsistency125is ... well ... inconsistent, but all right-thinking people know that126 (a) K&R are _right_ and (b) K&R are right. Besides, functions are127 special anyway (you can't nest them in C).128129 Note that the closing brace is empty on a line of its own, _except_ in130 the cases where it is followed by a continuation of the same statement,131 ie a "while"in a do-statement or an "else"in an if-statement, like132this:133135 body of do-loop136 } while (condition);137138 and139140if (x == y) {141 ..142 } else if (x > y) {143 ...144 } else {145 ....146 }147148 Rationale: K&R.149150 Also, note that this brace-placement also minimizes the number of empty151 (or almost empty) lines, without any loss of readability. Thus, as the152 supply of new-lines on your screen is not a renewable resource (think15325-line terminal screens here), you have more empty lines to put154 comments on.155156 Do not unnecessarily use braces where a single statement will do.157158if (condition)159 action();160161 and162163if (condition)164 do_this();165else166 do_that();167168 This does not apply if only one branch of a conditional statement is a single 169 statement; in the latter case use braces in both branches:170171if (condition) {172 do_this();173 do_that();174 } else {175 otherwise();176 }177178 3.1: Spaces179180 Linux kernel style for use of spaces depends (mostly) on181 function-versus-keyword usage. Use a space after (most) keywords. The 182 notable exceptions are sizeof, typeof, alignof, and __attribute__, which look 183 somewhat like functions (and are usually used with parentheses in Linux,184 although they are not required in the language, as in: "sizeof info" after 185"struct fileinfo info;"is declared).186187 So use a space after these keywords:188if, switch, case, for, do, while189 but not with sizeof, typeof, alignof, or __attribute__. E.g.,190 s = sizeof(struct file);191192 Do not add spaces around (inside) parenthesized expressions. This example is 193 *bad*:194195 s = sizeof( struct file );196197 When declaring pointer data or a function that returns a pointer type, the198 preferred use of '*'is adjacent to the data name or function name and not199 adjacent to the type name. Examples:200201char *linux_banner;202 unsigned long long memparse(char *ptr, char **retptr);203char *match_strdup(substring_t *s);204205 Use one space around (on each side of) most binary and ternary operators, 206 such as any of these:207208 = + - < > * / % | & ^ <= >= == != ? :209210 but no space after unary operators:211 & * + - ~ ! sizeof typeof alignof __attribute__ defined212213 no space before the postfix increment & decrement unary operators:214 ++ --215216 no space after the prefix increment & decrement unary operators:217 ++ --219 and no space around the '.' and "->" structure member operators.220221 Do not leave trailing whitespace at the ends of lines. Some editors with 222"smart" indentation will insert whitespace at the beginning of new lines as 223 appropriate, so you can start typing the next line of code right away.224 However, some such editors do not remove the whitespace if you end up not 225 putting a line of code there, such as if you leave a blank line. As a result, 226 you end up with lines containing trailing whitespace.227228 Git will warn you about patches that introduce trailing whitespace, and can 229 optionally strip the trailing whitespace for you; however, if applying a series 230 of patches, this may make later patches in the series fail by changing their 231 context lines.232233234 Chapter 4: Naming235236 C is a Spartan language, and so should your naming be. Unlike Modula-2 237 and Pascal programmers, C programmers do not use cute names like238 ThisVariableIsATemporaryCounter. A C programmer would call that239 variable "tmp", which is much easier to write, and not the least more240 difficult to understand.241242 HOWEVER, while mixed-case names are frowned upon, descriptive names for 243global variables are a must. To call a global function "foo"is a244 shooting offense.245246 GLOBAL variables (to be used only if you _really_ need them) need to247 have descriptive names, as do global functions. If you have a function248 that counts the number of active users, you should call that249"count_active_users()" or similar, you should _not_ call it "cntusr()".250251 Encoding the type of a function into the name (so-called Hungarian252 notation) is brain damaged - the compiler knows the types anyway and can 253 check those, and it only confuses the programmer. No wonder MicroSoft 254 makes buggy programs.255256 LOCAL variable names should be short, and to the point. If you have257 some random integer loop counter, it should probably be called "i".258 Calling it "loop_counter"is non-productive, if there is no chance of it259 being mis-understood. Similarly, "tmp" can be just about any type of260 variable that is used to hold a temporary value.261262 If you are afraid to mix up your local variable names, you have another263 problem, which is called the function-growth-hormone-imbalance syndrome. 264 See chapter 6 (Functions).265266267 Chapter 5: Typedefs268269 Please don't use things like "vps_t".270271 It's a _mistake_ to use typedef for structures and pointers. When you see a 272273 vps_t a;274275in the source, what does it mean?276277 In contrast, if it says278279struct virtual_container *a;280281 you can actually tell what "a"is.282283 Lots of people think that typedefs "help readability". Not so. They are284 useful only for:285286 (a) totally opaque objects (where the typedef is actively used to _hide_287 what the object is).288289 Example: "pte_t" etc. opaque objects that you can only access using290 the proper accessor functions.291292 NOTE! Opaqueness and "accessor functions" are not good in themselves. 293 The reason we have them for things like pte_t etc. is that there294 really is absolutely _zero_ portably accessible information there.295296 (b) Clear integer types, where the abstraction _helps_ avoid confusion297 whether it is"int" or "long".298299 u8/u16/u32 are perfectly fine typedefs, although they fit into300 category (d) better than here.301303"unsigned long", then there's no reason to do304305 typedef unsigned long myflags_t;306307 but if there is a clear reason for why it under certain circumstances308 might be an "unsigned int" and under other configurations might be 309"unsigned long", then by all means go ahead and use a typedef.310311 (c) when you use sparse to literally create a _new_ type for312 type-checking.313314 (d) New types which are identical to standard C99 types, in certain315 exceptional circumstances.316317 Although it would only take a short amount of time for the eyes and318 brain to become accustomed to the standard types like 'uint32_t',319 some people object to their use anyway.320321 Therefore, the Linux-specific 'u8/u16/u32/u64' types and their322 signed equivalents which are identical to standard types are323 permitted -- although they are not mandatory in new code of your324 own.325326 When editing existing code which already uses one or the other set327 of types, you should conform to the existing choices in that code.328329 (e) Types safe for use in userspace.330331 In certain structures which are visible to userspace, we cannot332 require C99 types and cannot use the 'u32' form above. Thus, we333 use __u32 and similar types in all structures which are shared334 with userspace.335336 Maybe there are other cases too, but the rule should basically be to NEVER 337 EVER use a typedef unless you can clearly match one of those rules.338339 In general, a pointer, or a struct that has elements that can reasonably340 be directly accessed should _never_ be a typedef.341342343 Chapter 6: Functions344345 Functions should be short and sweet, and do just one thing. They should346 fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,347as we all know), and do one thing and do that well.348349 The maximum length of a function is inversely proportional to the350 complexity and indentation level of that function. So, if you have a351 conceptually simple function that is just one long (but simple)352case-statement, where you have to do lots of small things for a lot of353 different cases, it's OK to have a longer function.354355 However, if you have a complex function, and you suspect that a356 less-than-gifted first-year high-school student might not even357 understand what the function is all about, you should adhere to the358 maximum limits all the more closely. Use helper functions with359 descriptive names (you can ask the compiler to in-line them if you think360 it's performance-critical, and it will probably do a better job of it361 than you would have done).362363 Another measure of the function is the number of local variables. They364 shouldn't exceed 5-10, or you're doing something wrong. Re-think the365 function, and split it into smaller pieces. A human brain can366 generally easily keep track of about 7 different things, anything more367 and it gets confused. You know you're brilliant, but maybe you'd like368 to understand what you did 2 weeks from now.369370 In source files, separate functions with one blank line. If the function is371 exported, the EXPORT* macro for it should follow immediately after the closing 372 function brace line. E.g.:373374int system_is_up(void)375 {376return system_state == SYSTEM_RUNNING;377 }378 EXPORT_SYMBOL(system_is_up);379380 In function prototypes, include parameter names with their data types.381 Although this is not required by the C language, it is preferred in Linux382 because it is a simple way to add valuable information for the reader.383384385 Chapter 7: Centralized exiting of functions387 Albeit deprecated by some people, the equivalent of the goto statement is388 used frequently by compilers in form of the unconditional jump instruction.389390 The goto statement comes in handy when a function exits from multiple391 locations and some common work such as cleanup has to be done.392393 The rationale is:394395 - unconditional statements are easier to understand and follow396 - nesting is reduced397 - errors by not updating individual exit points when making398 modifications are prevented399 - saves the compiler work to optimize redundant code away ;)400401int fun(int a)402 {403int result = 0;404char *buffer = kmalloc(SIZE);405406if (buffer == NULL)407return -ENOMEM;408409if (condition1) {410while (loop1) {411 ...412 }413 result = 1;414goto out;415 }416 ...417out:418 kfree(buffer);419return result;420 }421422 Chapter 8: Commenting423424 Comments are good, but there is also a danger of over-commenting. NEVER 425try to explain HOW your code works in a comment: it's much better to426 write the code so that the _working_ is obvious, and it's a waste of427 time to explain badly written code.428429 Generally, you want your comments to tell WHAT your code does, not HOW. 430 Also, try to avoid putting comments inside a function body: if the431 function is so complex that you need to separately comment parts of it,432 you should probably go back to chapter 6for a while. You can make433 small comments to note or warn about something particularly clever (or434 ugly), but try to avoid excess. Instead, put the comments at the head435 of the function, telling people what it does, and possibly WHY it does436 it.437438 When commenting the kernel API functions, please use the kernel-doc format. 439 See the files Documentation/kernel-doc-nano-HOWTO.txt and scripts/kernel-doc 440for details.441442 Linux style for comments is the C89 "/* ... */" style.443 Don't use C99-style "// ..." comments.444445 The preferred style for long (multi-line) comments is:446447/*448 * This is the preferred style for multi-line449 * comments in the Linux kernel source code.450 * Please use it consistently.451 *452 * Description: A column of asterisks on the left side,453 * with beginning and ending almost-blank lines.454*/455456 For files in net/ and drivers/net/ the preferred style for long (multi-line)457 comments is a little different.458459/* The preferred comment style for files in net/ and drivers/net460 * looks like this.461 *462 * It is nearly the same as the generally preferred comment style,463 * but there is no initial almost-blank line.464*/465466 It's also important to comment data, whether they are basic types or derived 467 types. To this end, use just one data declaration per line (no commas for468 multiple data declarations). This leaves you room for a small comment on each 469 item, explaining its use.472 Chapter 9: You've made a mess of it473474 That's OK, we all do. You've probably been told by your long-time Unix 475 user helper that "GNU emacs" automatically formats the C sources for476 you, and you've noticed that yes, it does do that, but the defaults it477 uses are less than desirable (in fact, they are worse than random478 typing - an infinite number of monkeys typing into GNU emacs would never 479 make a good program).480481 So, you can either get rid of GNU emacs, or change it to use saner482 values. To do the latter, you can stick the following in your .emacs file: 483484 (defun c-lineup-arglist-tabs-only (ignored)485"Line up argument lists by tabs, not spaces"486 (let* ((anchor (c-langelem-pos c-syntactic-element))487 (column (c-langelem-2nd-pos c-syntactic-element))488 (offset (- (1+ column) anchor))489 (steps (floor offset c-basic-offset)))490 (* (max steps 1)491 c-basic-offset)))492493 (add-hook 'c-mode-common-hook494 (lambda ()495 ;; Add kernel style496 (c-add-style497"linux-tabs-only"498'("linux" (c-offsets-alist499 (arglist-cont-nonempty500 c-lineup-gcc-asm-reg501 c-lineup-arglist-tabs-only))))))502503 (add-hook 'c-mode-hook504 (lambda ()505 (let ((filename (buffer-file-name)))506 ;; Enable kernel mode for the appropriate files507 (when (and filename508 (string-match (expand-file-name "~/src/linux-trees")509 filename))510 (setq indent-tabs-mode t)511 (c-set-style "linux-tabs-only")))))512513 This will make emacs go better with the kernel coding style for C514 files below ~/src/linux-trees.515516 But even if you fail in getting emacs to do sane formatting, not517 everything is lost: use "indent".518519 Now, again, GNU indent has the same brain-dead settings that GNU emacs 520 has, which is why you need to give it a few command line options.521 However, that's not too bad, because even the makers of GNU indent522 recognize the authority of K&R (the GNU people aren't evil, they are523 just severely misguided in this matter), so you just give indent the524 options "-kr -i8" (stands for"K&R, 8 character indents"), or use 525"scripts/Lindent", which indents in the latest style.526527"indent" has a lot of options, and especially when it comes to comment 528 re-formatting you may want to take a look at the man page. But529 remember: "indent"is not a fix for bad programming.530531532 Chapter 10: Kconfig configuration files533534 For all of the Kconfig* configuration files throughout the source tree,535 the indentation is somewhat different. Lines under a "config" definition536 are indented with one tab, while help text is indented an additional two537 spaces. Example:538539 config AUDIT540bool"Auditing support"541 depends on NET542 help543 Enable auditing infrastructure that can be used with another544 kernel subsystem, such as SELinux (which requires this for545 logging of avc messages output). Does not do system-call546 auditing without CONFIG_AUDITSYSCALL.547548 Features that might still be considered unstable should be defined as549 dependent on "EXPERIMENTAL":550551 config SLUB552 depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT 553bool"SLUB (Unqueued Allocator)"556while seriously dangerous features (such as write support for certain557 filesystems) should advertise this prominently in their prompt string:558559 config ADFS_FS_RW560bool"ADFS write support (DANGEROUS)"561 depends on ADFS_FS562 ...563564 For full documentation on the configuration files, see the file565 Documentation/kbuild/kconfig-language.txt.566567568 Chapter 11: Data structures569570 Data structures that have visibility outside the single-threaded571 environment they are created and destroyed in should always have572 reference counts. In the kernel, garbage collection doesn't exist (and573 outside the kernel garbage collection is slow and inefficient), which574 means that you absolutely _have_ to reference count all your uses.575576 Reference counting means that you can avoid locking, and allows multiple 577 users to have access to the data structure in parallel - and not having578 to worry about the structure suddenly going away from under them just579 because they slept or did something else for a while.580581 Note that locking is _not_ a replacement for reference counting.582 Locking is used to keep data structures coherent, while reference583 counting is a memory management technique. Usually both are needed, and 584 they are not to be confused with each other.585586 Many data structures can indeed have two levels of reference counting,587 when there are users of different "classes". The subclass count counts588 the number of subclass users, and decrements the global count just once 589 when the subclass count goes to zero.590591 Examples of this kind of "multi-level-reference-counting" can be found in592 memory management ("struct mm_struct": mm_users and mm_count), and in 593 filesystem code ("struct super_block": s_count and s_active).594595 Remember: if another thread can find your data structure, and you don't596 have a reference count on it, you almost certainly have a bug.597598599 Chapter 12: Macros, Enums and RTL600601 Names of macros defining constants and labels in enums are capitalized. 602603#define CONSTANT 0x12345604605 Enums are preferred when defining several related constants.606607 CAPITALIZED macro names are appreciated but macros resembling functions 608 may be named in lower case.609610 Generally, inline functions are preferable to macros resembling functions. 611612 Macros with multiple statements should be enclosed in a do - while block: 613614#define macrofun(a, b, c) \615do { \616if (a == 5) \617 do_this(b, c); \618 } while (0)619620 Things to avoid when using macros:6216221) macros that affect control flow:623624#define FOO(x) \625do { \626if (blah(x) < 0) \627return -EBUGGERED; \628 } while(0)629630is a _very_ bad idea. It looks like a function call but exits the "calling"631 function; don't break the internal parsers of those who will read the code.6326332) macros that depend on having a local variable with a magic name:634635#define FOO(val) bar(index, val)636637 might look like a good thing, but it's confusing as hell when one reads the6403) macros with arguments that are used as l-values: FOO(x) = y; will641 bite you if somebody e.g. turns FOO into an inline function.6426434) forgetting about precedence: macros defining constants using expressions644 must enclose the expression in parentheses. Beware of similar issues with645 macros using parameters.646647#define CONSTANT 0x4000648#define CONSTEXP (CONSTANT | 3)649650 The cpp manual deals with macros exhaustively. The gcc internals manual also 651 covers RTL which is used frequently with assembly language in the kernel.652653654 Chapter 13: Printing kernel messages655656 Kernel developers like to be seen as literate. Do mind the spelling657 of kernel messages to make a good impression. Do not use crippled658 words like "dont"; use "do not" or "don't" instead. Make the messages659 concise, clear, and unambiguous.660661 Kernel messages do not have to be terminated with a period.662663 Printing numbers in parentheses (%d) adds no value and should be avoided.664665 There are a number of driver model diagnostic macros in <linux/device.h>666 which you should use to make sure messages are matched to the right device 667 and driver, and are tagged with the right level: dev_err(), dev_warn(),668 dev_info(), and so forth. For messages that aren't associated with a669 particular device, <linux/printk.h> defines pr_debug() and pr_info().670671 Coming up with good debugging messages can be quite a challenge; and once 672 you have them, they can be a huge help for remote troubleshooting. Such673 messages should be compiled out when the DEBUG symbol is not defined (that 674is, by default they are not included). When you use dev_dbg() or pr_debug(),675 that's automatic. Many subsystems have Kconfig options to turn on -DDEBUG. 676 A related convention uses VERBOSE_DEBUG to add dev_vdbg() messages to the 677 ones already enabled by DEBUG.678679680 Chapter 14: Allocating memory681682 The kernel provides the following general purpose memory allocators:683 kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc(), and684 vzalloc(). Please refer to the API documentation for further information685 about them.686687 The preferred form for passing a size of a struct is the following:688689 p = kmalloc(sizeof(*p), ...);690691 The alternative form where struct name is spelled out hurts readability and692 introduces an opportunity for a bug when the pointer variable type is changed693 but the corresponding sizeof that is passed to a memory allocator is not.694695 Casting the return value which is a void pointer is redundant. The conversion696from void pointer to any other pointer type is guaranteed by the C programming 697 language.698699 The preferred form for allocating an array is the following:700701 p = kmalloc_array(n, sizeof(...), ...);702703 The preferred form for allocating a zeroed array is the following:704705 p = kcalloc(n, sizeof(...), ...);706707 Both forms check for overflow on the allocation size n * sizeof(...),708 and return NULL if that occurred.709710711 Chapter 15: The inline disease712713 There appears to be a common misperception that gcc has a magic "make me 714 faster" speedup option called "inline". While the use of inlines can be715 appropriate (for example as a means of replacing macros, see Chapter 12), it716 very often is not. Abundant use of the inline keyword leads to a much bigger717 kernel, which in turn slows the system as a whole down, due to a bigger718 icache footprint for the CPU and simply because there is less memory719 available for the pagecache. Just think about it; a pagecache miss causes a720 disk seek, which easily takes 5 milliseconds. There are a LOT of cpu cycles721 that can go into these 5 milliseconds.。
linux 的编码格式
linux 的编码格式Linux的编码格式简介:Linux是一种开源操作系统,广泛应用于各个领域。
在Linux系统中,编码格式是一个关键的概念,它决定了如何表示和存储文本数据。
本文将介绍常见的Linux编码格式及其特点,以及在使用Linux系统时应该注意的问题。
一、ASCII编码ASCII(American Standard Code for Information Interchange)是最早的字符编码标准,在计算机中使用7位二进制数来表示字符。
它定义了128个字符,包括大写和小写字母、数字以及一些常见的符号,如英文标点符号和控制字符。
由于ASCII编码只能表示有限的字符集合,不能满足国际化需求,因此逐渐被更全面的编码格式所取代。
二、UTF-8编码UTF-8(Unicode Transformation Format-8bit)是一种可变长度的Unicode编码标准,支持全球范围内的字符集。
UTF-8编码在Linux系统中被广泛使用,因为它能够兼容ASCII编码。
UTF-8使用1至4个字节来表示一个字符,具备良好的兼容性和可扩展性。
它可以表示几乎所有的字符,包括汉字、拉丁字母、希腊字母等。
UTF-8编码是Linux系统默认的字符编码格式。
三、GBK编码GBK编码是中国国家标准的字符集,它是对GB2312编码的扩充,能够覆盖更多的中文字符。
GBK编码使用2个字节表示一个字符,其中包含了21003个汉字和符号以及部分非汉字字符。
在Linux系统中,如果需要处理中文字符的文本数据,可以选择使用GBK编码来存储和表示。
四、其他编码格式除了ASCII、UTF-8和GBK编码外,Linux还支持其他一些编码格式,如UTF-16、ISO-8859等。
这些编码格式通常用于特定的情况和需求,比如在处理特定语言或特定文件格式时使用。
五、在Linux系统中选择编码格式的注意事项1. 考虑文本数据的应用场景和需求。
Linux内核编程规范与代码风格
Linux内核编程规范与代码风格这是⼀篇阐述Linux内核编程代码风格的⽂档,译者以学习为⽬的进⾏翻译。
1 缩进Tab的宽度是⼋个字符,因此缩进的宽度也是⼋个字符。
有些异教徒想让缩进变成四个字符,甚⾄是两个字符的宽度,这些⼈和那些把 PI 定义为 3 的⼈是⼀个路⼦的。
注意:缩进的全部意义在于清晰地定义语句块的开始与结束,特别是当你盯着屏幕20个⼩时之后,你会发现长的缩进宽度的作⽤。
现在有些⼈说⼋个字符的宽度太宽了,这会让代码往右移很远,在⼀块⼋⼗字符宽的屏幕上,这样的代码会很难阅读。
对此的回答是,如果你写的代码需要超过三层的缩进,那么你把⼀切都搞砸了,你应该修复你的程序。
简⽽⾔之,⼋个字符宽度的缩进让代码更容易阅读,并且额外的好处就是提醒你,不要在⼀个函数⾥写太多层的嵌套逻辑。
请记住这个警⽰。
switch语句的缩进⽅式是让case与switch对齐:switch (suffix) {case 'G':case 'g':mem <<= 30;break;case 'M':case 'm':mem <<= 20;break;case 'K':case 'k':mem <<= 10;/* fall through */default:break;}不要在单独⼀⾏⾥写多个语句,除⾮你想⼲什么不为⼈知的事:if (condition) do_this;do_something_everytime;对了,不要把多个赋值语句放在同⼀⾏,内核的代码风格是⼗分简洁的,请尽量避免使⽤复杂的表达式。
除了在注释、⽂档和Kconfig中,永远不要使⽤空格作为缩进,上⾯的例⼦是故意犯的错误。
找⼀个像样的编辑器,不要在⾏末留有空格。
2 换⾏规范代码风格的⽬的是提⾼代码的可读性和维护性。
单⾏的宽度限制为⼋⼗列,这是强烈推荐的设置。
linux 的编码格式
linux 的编码格式摘要:1.Linux 的编码格式简介2.Linux 中常用的编码格式3.Linux 编码格式设置方法4.编码格式对Linux 系统的影响5.总结正文:Linux 的编码格式--------------------Linux 作为一种广泛应用于服务器和嵌入式系统的操作系统,支持多种编码格式。
编码格式是用于表示文本或字符的一种规则,不同的编码格式可能导致相同字符的存储和显示方式不同。
本文将为您介绍Linux 的编码格式以及相关设置方法。
Linux 中常用的编码格式----------------------在Linux 中,常用的编码格式包括:1.ASCII 编码:最早的字符编码格式,包括32 个通用控制字符和128 个字符,可以表示英文字母、数字和一些符号。
2.ISO-8859-1 编码(Latin-1 编码):基于ASCII 编码,扩展了字符集,包括128 个字符,可以表示大多数西欧语言的字符。
3.UTF-8 编码:一种广泛应用的编码格式,可以表示世界上几乎所有的字符,包括中文、日文和韩文等。
UTF-8 编码使用可变长度的编码方式,占用存储空间相对较大,但具有很好的兼容性。
4.UTF-16 编码:另一种广泛应用的编码格式,采用固定长度16 位编码,适用于处理Unicode 字符集中的字符,但对于英文字符的存储空间相对较大。
5.UTF-32 编码:采用固定长度32 位编码,可以表示Unicode 字符集中的所有字符,但对于英文字符的存储空间较大。
Linux 编码格式设置方法--------------------在Linux 中,可以通过以下方法设置编码格式:1.使用`export`命令设置环境变量:在终端中输入`exportLANG=”en_US.UTF-8″`,可以设置系统默认编码为UTF-8。
2.修改`/etc/locale.gen`文件:使用`locale-gen`命令生成相应的`/etc/locale.gen`文件,然后编辑该文件,设置相应的编码格式。
Linux内核源代码(free)
Linux系统的好处 Linux的运行及相关基本概念
什么是Linux?
Linux是一个类Unix(Unix-like)的操作系统, 在1991年发行了它的第一个版本 在Linux内核维护网站上,“What is Linux?”
Portable Operating System Interface Standard 可移植操作系统接口标准 由IEEE制订,并由ISO接受为国际标准。 Institute for Electrical and Electronic Engineers 电气电子工程师学会[美] International Organization for Standardization 国际标准化组织 制定各行各业各种产品和服务的技术规范(国际标准)
Linux简介
什么是Linux? “Linux”在不同的语境下的含义 Linux发展简史 Linux操作系统的主要内容 Linux版本
内核版本 发行版本
Linux系统的好处 Linux的运行及相关基本概念
“Linux”
在不同的语境下,“Linux”具有不同的内涵,例 如:
Linux发展简史
1991年11月,芬兰赫尔辛基大学的学生 Linus Torvalds写了个小程序,后来取名为Linux,放在 互联网上。他表达了一个愿望,希望借此搞出一 个操作系统的“内核”来,这完全是一个偶然事 件 1993,在一批高水平黑客的参与下,诞生了Linux 1.0 版 1994年,Linux 的第一个商业发行版 Slackware 问 世
基于I386的Linux使用int 0x80进行系统调用
I386系统的基本概念
代码的运行 堆栈的概念 内核态与用户态 中断/异常/系统调用 虚拟内存
计算机编程的代码规范与风格
计算机编程的代码规范与风格代码是计算机程序的核心组成部分,良好的代码质量对于编程的可读性、可维护性和可扩展性都有着重要的影响。
为了提高代码质量,程序员们开发了一系列的代码规范和编程风格。
一、命名规范1. 变量、函数和类名应该使用有意义、清晰易懂的名字,避免使用无意义的缩写或者单个字母来表示。
2. 变量名的命名规范推荐使用小写字母和下划线,例如:count, max_value。
3. 函数名的命名规范推荐使用小驼峰式命名法,例如:getUserName, calculateArea。
4. 类名的命名规范推荐使用大驼峰式命名法,例如:UserInfo, StudentInfo。
二、缩进和空格1. 代码缩进应该使用4个空格或者Tab,保持代码的整洁。
2. 运算符两边应该添加空格,例如:a = b + c。
3. 函数之间应该用空行进行分隔,提高代码的可读性。
三、注释规范1. 每个函数、方法和类应该添加注释,说明其功能、参数和返回值等重要信息。
2. 注释应该使用清晰、简洁的语言,避免使用拗口的技术术语。
3. 注释应该与代码保持同步更新,避免注释与实际代码功能不一致。
四、代码重构1. 遵循“单一职责原则”,每个函数或者类只负责完成一个具体的功能。
2. 避免代码重复,提取公共代码,将其封装成函数或者类。
3. 提高代码的模块性,使得代码结构清晰,易于理解和维护。
五、错误处理和异常处理1. 合理利用异常处理机制,对可能抛出异常的代码进行适当的处理。
2. 使用try-catch语句块捕获异常并进行错误处理,避免程序崩溃。
六、代码版本管理1. 使用代码版本管理工具,如Git,保持代码的版本控制和追踪。
2. 每次修改代码前先进行代码备份,以防止意外修改导致的代码丢失。
七、代码测试和调试1. 编写代码时应提前设计好测试用例,对代码进行全面的测试。
2. 使用断言(assertion)来验证代码逻辑的正确性。
3. 在进行代码调试时,使用适当的调试工具和技巧,定位和修复问题。
Linux内核源码及其分析
深入分析Linux内核源码前言第一章走进linux1.1 GNU与Linux的成长1.2 Linux的开发模式和运作机制1.3走进Linux内核1.3.1 Linux内核的特征1.3.2 Linux内核版本的变化1.4 分析Linux内核的意义1.4.1 开发适合自己的操作系统1.4.2 开发高水平软件1.4.3 有助于计算机科学的教学和科研1.5 Linux内核结构1.5.1 Linux内核在整个操系统中的位置1.5.2 Linux内核的作用1.5.3 Linux内核的抽象结构1.6 Linux内核源代码1.6.1 多版本的内核源代码1.6.2 Linux内核源代码的结构1.6.3 从何处开始阅读源代码1.7 Linux内核源代码分析工具1.7.1 Linux超文本交叉代码检索工具1.7.2 Windows平台下的源代码阅读工具Source Insight第二章Linux运行的硬件基础2.1 i386的寄存器2.1.1通用寄存器2.1.2段寄存器2.1.3状态和控制寄存器2.1.4 系统地址寄存器2.1.5 调试寄存器和测试寄存器2.2 内存地址2.3 段机制和描述符2.3.1 段机制2.3.2 描述符的概念2.3.3系统段描述符2.3.4 描述符表2.3.5 选择符与描述符表寄存器2.3.6 描述符投影寄存器2.3.7 Linux中的段2.4 分页机制2.4.1 分页机构2.4.2页面高速缓存2.5 Linux中的分页机制2.5.1 与页相关的数据结构及宏的定义2.5.2 对页目录及页表的处理2.6 Linux中的汇编语言2.6.1 A T&T与Intel汇编语言的比较2.6.2 A T&T汇编语言的相关知识2.6.3 Gcc嵌入式汇编2.6.4 Intel386汇编指令摘要第三章中断机制3.1 中断基本知识3.1.1 中断向量3.1.2 外设可屏蔽中断3.1.3异常及非屏蔽中断3.1.4中断描述符表3.1.5 相关汇编指令3.2中断描述符表的初始化3.2. 1 外部中断向量的设置3.2.2中断描述符表IDT的预初始化3.2.3 中断向量表的最终初始化3.3异常处理3.3.1 在内核栈中保存寄存器的值3.3.2 中断请求队列的初始化3.3.3中断请求队列的数据结构3.4 中断处理3.4.1中断和异常处理的硬件处理3.4.2 Linux对异常和中断的处理3.4.3 与堆栈有关的常量、数据结构及宏3.4.4 中断处理程序的执行3.4.5 从中断返回3.5中断的后半部分处理机制3.5.1 为什么把中断分为两部分来处理3.5.2 实现机制3.5.3数据结构的定义3.5.4 软中断、bh及tasklet的初始化3.5.5后半部分的执行3.5.6 把bh移植到tasklet第四章进程描述4.1 进程和程序(Process and Program)4.2 Linux中的进程概述4.3 task_struct结构描述4.4 task_struct结构在内存中的存放4.4.1 进程内核栈4.4.2 当前进程(current宏)4.5 进程组织的方式4.5.1哈希表4.5.2双向循环链表4.5.3 运行队列4.5.4 等待队列4.6 内核线程4.7 进程的权能4.8 内核同步4.8.1信号量4.8.2原子操作4.8.3 自旋锁、读写自旋锁和大读者自旋锁4.9 本章小节第五章进程调度5.1 Linux时间系统5.1.1 时钟硬件5.1.2 时钟运作机制5.1.3 Linux时间基准5.1.4 Linux的时间系统5.2 时钟中断5.2.1 时钟中断的产生5.2.2.Linux实现时钟中断的全过程5.3 Linux的调度程序-Schedule( )5.3.1 基本原理5.3.2 Linux进程调度时机5.3.3 进程调度的依据5.3.4 进程可运行程度的衡量5.3.5 进程调度的实现5.4 进程切换5.4.1 硬件支持5.4.2 进程切换第六章Linux内存管理6.1 Linux的内存管理概述6.1.1 Linux虚拟内存的实现结构6.1.2 内核空间和用户空间6.1.3 虚拟内存实现机制间的关系6.2 Linux内存管理的初始化6.2.1 启用分页机制6.2.2 物理内存的探测6.2.3 物理内存的描述6.2.4 页面管理机制的初步建立6.2.5页表的建立6.2.6内存管理区6.3 内存的分配和回收6.3.1 伙伴算法6.3.2 物理页面的分配和释放6.3.3 Slab分配机制6.4 地址映射机制6.4.1 描述虚拟空间的数据结构6.4.2 进程的虚拟空间6.4.3 内存映射6.5 请页机制6.5.1 页故障的产生6.5.2 页错误的定位6.5.3 进程地址空间中的缺页异常处理6.5.4 请求调页6.5.5 写时复制6.6 交换机制6.6.1 交换的基本原理6.6.2 页面交换守护进程kswapd6.6.3 交换空间的数据结构6.6.4 交换空间的应用6.7 缓存和刷新机制6.7.1 Linux使用的缓存6.7.2 缓冲区高速缓存6.7.3 翻译后援存储器(TLB)6.7.4 刷新机制6.8 进程的创建和执行6.8.1 进程的创建6.8.2 程序执行6.8.3 执行函数第七章进程间通信7.1 管道7.1.1 Linux管道的实现机制7.1.2 管道的应用7.1.3 命名管道(FIFO)7.2 信号(signal)7.2.1 信号种类7.2.2 信号掩码7.2.3 系统调用7.2.4 典型系统调用的实现7.2.5 进程与信号的关系7.2.6 信号举例7.3 System V 的IPC机制7.3.1 信号量7.3.2 消息队列7.3.3 共享内存第八章虚拟文件系统8.1 概述8.2 VFS中的数据结构8.2.1 超级块8.2.2 VFS的索引节点8.2.3 目录项对象8.2.4 与进程相关的文件结构8.2.5 主要数据结构间的关系8.2.6 有关操作的数据结构8.3 高速缓存8.3.1 块高速缓存8.3.2 索引节点高速缓存8.3.3 目录高速缓存8.4 文件系统的注册、安装与拆卸8.4.1 文件系统的注册8.4.2 文件系统的安装8.4.3 文件系统的卸载8.5 限额机制8.6 具体文件系统举例8.6.1 管道文件系统pipefs8.6.2 磁盘文件系统BFS8.7 文件系统的系统调用8.7.1 open 系统调用8.7.2 read 系统调用8.7.3 fcntl 系统调用8 .8 Linux2.4文件系统的移植问题第九章Ext2文件系统9.1 基本概念9.2 Ext2的磁盘布局和数据结构9.2.1 Ext2的磁盘布局9.2.2 Ext2的超级块9.2.3 Ext2的索引节点9.2.4 组描述符9.2.5 位图9.2.6 索引节点表及实例分析9.2.7 Ext2的目录项及文件的定位9.3 文件的访问权限和安全9.4 链接文件9.5 分配策略9.5.1 数据块寻址9.5.2 文件的洞9.5.3 分配一个数据块第十章模块机制10.1 概述10.1.1 什么是模块10.1.2 为什么要使用模块?10.2 实现机制10.2.1 数据结构10.2.2 实现机制的分析10.3 模块的装入和卸载10.3.1 实现机制10.3.2 如何插入和卸载模块10.4 内核版本10.4.1 内核版本与模块版本的兼容性10.4.2 从版本2.0到2.2内核API的变化10.4.3 把内核2.2移植到内核2.410.5 编写内核模块10.5.1 简单内核模块的编写10.5.2 内核模块的Makefiles文件10.5.3 内核模块的多个文件第十一章设备驱动程序11.1 概述11.1.1 I/O软件11.1.2 设备驱动程序11.2 设备驱动基础11.2.1 I/O端口11.2.2 I/O接口及设备控制器11.2.3 设备文件11.2.4 VFS对设备文件的处理11.2.5 中断处理11.2.6 驱动DMA工作11.2.7 I/O 空间的映射11.2.8 设备驱动程序框架11.3 块设备驱动程序11.3.1 块设备驱动程序的注册11.3.2 块设备基于缓冲区的数据交换11.3.3 块设备驱动程序的几个函数11.3.4 RAM 盘驱动程序的实现11.3.5 硬盘驱动程序的实现11.4 字符设备驱动程序11.4.1 简单字符设备驱动程序11.4.2 字符设备驱动程序的注册11.4.3 一个字符设备驱动程序的实例11.4.4 驱动程序的编译与装载第十二章网络12.1 概述12.2 网络协议12.2.1 网络参考模型12.2.2 TCP/IP协议工作原理及数据流12.2.3 Internet 协议12.2.4 TCP协议12.3 套接字(socket)12.3.1 套接字在网络中的地位和作用12.3.2 套接字接口的种类12.3.3 套接字的工作原理12.3.4 socket 的通信过程12.3.5 socket为用户提供的系统调用12.4 套接字缓冲区(sk_buff)12.4.1 套接字缓冲区的特点12.4.2 套接字缓冲区操作基本原理12.4.3 sk_buff数据结构的核心内容12.4.4 套接字缓冲区提供的函数12.4.5 套接字缓冲区的上层支持例程12.5 网络设备接口12.5.1 基本结构12.5.2 命名规则12.5.3 设备注册12.5.4 网络设备数据结构12.5.5 支持函数第十三章启动系统13.1 初始化流程13.1.1 系统加电或复位13.1.2 BIOS启动13.1.3 Boot Loader13.1.4 操作系统的初始化13.2 初始化的任务13.2.1 处理器对初始化的影响13.2.2 其他硬件设备对处理器的影响13.3 Linux 的Boot Loarder13.3.1 软盘的结构13.3.2 硬盘的结构13.3.3 Boot Loader13.3.4 LILO13.3.5 LILO的运行分析13.4 进入操作系统13.4.1 Setup.S13.4.2 Head.S13.5 main.c中的初始化13.6 建立init进程13.6.1 init进程的建立13.6.2 启动所需的Shell脚本文件附录:1 Linux 2.4内核API2.1驱动程序的基本函数2.2 双向循环链表的操作2.3 基本C库函数2.4 Linux内存管理中Slab缓冲区2.5 Linux中的VFS2.6 Linux的连网2.7 网络设备支持2.8 模块支持2.9 硬件接口2.10 块设备2.11 USB 设备2 参考文献前言Linux内核全部源代码是一个庞大的世界,大约有200多万行,占60MB左右的空间。
linux 的编码格式
linux 的编码格式【原创版】目录1.Linux 编码格式简介2.Linux 编码格式的发展历程3.Linux 编码格式的主要种类4.Linux 编码格式的应用实例5.Linux 编码格式的发展趋势正文【1.Linux 编码格式简介】Linux 编码格式是指在 Linux 操作系统中使用的字符编码方式。
由于 Linux 系统是一个多语言、多文化的操作系统,因此其编码格式也呈现出多样化的特点。
Linux 编码格式主要包括 UTF-8、GBK、GB2312 等,这些编码格式能够涵盖世界上大部分语言和字符。
【2.Linux 编码格式的发展历程】Linux 编码格式的发展经历了多个阶段。
最初,Linux 系统主要使用ASCII 编码,这种编码方式只能表示 128 个字符。
随着计算机的发展和信息交流的需求,Linux 系统开始采用更多的字符编码方式,比如ISO-8859-1,这种编码方式可以表示 256 个字符。
然而,这些编码方式仍然不能满足世界上所有语言和字符的需求。
因此,在 90 年代末,UTF-8 编码格式开始被广泛采用。
UTF-8 编码可以表示世界上所有语言和字符,并且具有字节顺序无关、可变长度等优点。
【3.Linux 编码格式的主要种类】Linux 编码格式主要包括 UTF-8、GBK、GB2312 等。
其中,UTF-8 编码是目前最常用的编码方式,它可以表示任何语言和字符。
GBK 和 GB2312 编码则是针对中文设计的编码方式,它们可以表示简体中文和繁体中文。
【4.Linux 编码格式的应用实例】在 Linux 系统中,编码格式的应用非常广泛。
比如,在编辑文本文件时,我们需要选择正确的编码格式来保存文件,以便于其他系统或程序能够正确地读取文件。
此外,在网络传输中,编码格式也起着重要的作用。
例如,在网页开发中,我们需要使用 UTF-8 编码来保证网页能够在各种设备和操作系统上正确显示。
【5.Linux 编码格式的发展趋势】随着计算机技术的发展和信息交流的加快,Linux 编码格式的发展趋势呈现出多元化和标准化的特点。
Linux内核调试机制源代码分析
kimage_entry_t *entry; kimage_entry_t *last_entry; unsigned long destination; unsigned long start; struct page *control_code_page; struct page *swap_page; unsigned long nr_segments; struct kexec_segment segment[KEXEC_SEGMENT_MAX]; /*段数组*/ struct list_head control_pages; struct list_head dest_pages; struct list_head unuseable_pages; /* 分配给崩溃内核的下一个控制页的地址*/ unsigned long control_page; /* 指定特殊处理的标识*/ unsigned int type : 1; #define KEXEC_TYPE_DEFAULT 0 #define KEXEC_TYPE_CRASH 1 unsigned int preserve_context : 1; };
内核 kexec 接口函数说明如下:
extern void machine_kexec(struct kimage *image); /*启动内核映像*/ extern int machine_kexec_prepare(struct kimage *image); /*建立内核映 像所需要的控制页*/ extern void machine_kexec_cleanup(struct kimage *image); extern asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, unsigned long flags); /*装 载内核的系统调用*/ extern int kernel_kexec(void); /*启动内核*/
linux内核版本编号规则
linux内核版本编号规则Linux内核版本编号规则Linux内核作为开源操作系统的核心,其版本编号规则是一个非常重要的内容。
正确理解和应用内核版本编号规则,对于操作系统的开发、维护和升级都具有重要意义。
本文将从不同的角度解读Linux内核版本编号规则,并探讨其中的含义和作用。
一、版本编号规则的基本原则Linux内核版本编号遵循的基本原则是"主版本号.次版本号.修订版本号"的格式。
其中,主版本号表示内核的重大更新,次版本号表示功能的增加或改进,修订版本号表示错误修复。
内核版本号中的各个部分都有特定的含义和作用,下面将对其进行详细解释。
1. 主版本号主版本号是内核版本编号中的第一个数字,它表示内核的重大更新。
通常情况下,主版本号的增加意味着内核发生了较大的改变,可能引入了新的功能、架构或者重要的优化。
主版本号的增加可能导致旧有的应用无法兼容,需要进行相应的适配和更新。
2. 次版本号次版本号是内核版本编号中的第二个数字,它表示功能的增加或改进。
当内核的功能得到了扩展或者改进时,次版本号会增加。
次版本号的增加通常不会影响应用的兼容性,但是可能需要重新编译和部署应用程序。
3. 修订版本号修订版本号是内核版本编号中的第三个数字,它表示错误修复。
当内核中发现了错误或者漏洞时,修订版本号会增加。
修订版本号的增加通常不会引入新的功能或者改变现有功能,只会修复已知的问题。
二、版本编号规则的实际应用Linux内核版本编号规则在实际应用中有着重要的意义。
通过观察内核版本号的变化,我们可以了解到内核的更新情况、功能改进和错误修复等信息。
同时,版本编号规则也为开发者和用户提供了一些有用的参考。
1. 版本号的递增关系根据版本编号规则,我们可以得出以下结论:- 主版本号的增加意味着内核发生了较大的改变,可能导致旧有的应用无法兼容。
- 次版本号的增加表示内核功能得到了扩展或者改进,不会影响应用的兼容性。
- 修订版本号的增加表示内核中发现了错误或者漏洞,需要进行相应的修复。
完整版Linux内核代码风格
.. } else if (x > y) {
... } else {
.... } 理由:K&R。 也请注意这种大括号的放置方式也能使空(或者差不多空的)行的数量最小化,同时不失可读性。因此,由于你的屏 幕上的新行的供应不是可回收的资源(想想 25 行的终端屏幕),你将会有更多的空行来放置注释。 当只有一个单独的语句的时候,不用加不必要的大括号。 if (condition) action(); 这点不适用于本身为某个条件语句的一个分支的单独语句。这时需要在两个分支里都使用大括号。 if (condition) { do_this(); do_that(); } else { otherwise(); } 3.1:空格 Linux 内核的空格使用方式(主要)取决于它是用于函数还是关键字。(大多数)关键字后要加一个空格。值得注意的 例外是 sizeof、typeof、alignof 和__attribute__,这些关键字某些程度上看起来更像函数(它们在 Linux 里也常常伴随小 括号而使用,尽管在 C 语言里这样的小括号不是必需的,就像“struct fileinfo info”声明过后的“sizeof info”)。 所以,在这些关键字之后放一个空格: if, switch, case, for, do, while 但是不要在 sizeof、typeof、alignof 或者__attribute__这些关键字之后放空格。例如: s = sizeof(struct file); 不要在小括号里的表达式两侧加空格。这是一个反例: s = sizeof( struct file ); 当声明指针类型或者返回指针类型的函数时,“*”的首选使用方式是使之靠近变量名或者函数名,而不是靠近类型名。 例子: char *linux_banner; unsigned long long memparse(char *ptr, char **retptr); char *match_strdup(substring_t *s); 在大多数二元和三元操作符两侧使用一个空格,例如下面所有这些操作符: = - < > * / % | & ^ <= >= == != ? : 但是一元操作符后不要加空格: & * - ~ ! sizeof typeof alignof __attribute__ defined 后缀自加和自减一元操作符前不加空格: -前缀自加和自减一元操作符后不加空格: -“.”和“->”结构体成员操作符前后不加空格。 不要在行尾留空白。有些可以自动缩进的编辑器会在新行的行首加入适量的空白,然后你就可以直接在那一行输入代
linux 内核c语言标准
linux 内核c语言标准Linux内核主要是用C语言编写的。
这是因为C语言是一种通用、过程式的计算机程序设计语言,能够直接对硬件进行操作,并且具有可移植性强的特点,非常适合用来编写操作系统。
在Linux内核中,C语言的版本是C99,这是因为Linux内核开发人员在编写代码时遵守的是C99标准。
C99标准是C语言的一个版本,它在C90标准的基础上增加了一些新的特性和改进,例如支持可变参数宏、增强了对类型的支持、增加了新的数据类型等。
除了C语言标准之外,Linux内核还遵循了一些其他的编程规范和约定,例如命名规范、注释规范、代码风格等。
这些规范和约定有助于提高代码的可读性和可维护性,以及确保代码的一致性和正确性。
总的来说,Linux内核的编程语言是C语言,并且遵循C99标准和其他一些编程规范和约定。
Linux内核的版本可以从两个方面来分类:版本号和发布类型。
版本号:Linux内核的版本号由四个部分组成,包括主版本号、次版本号、修订次数和微调次数。
主版本号和次版本号用来表示内核的重大更改,其中主版本号表示内核的重大更新,次版本号表示新增功能或对原有功能的修改。
修订次数用来表示对内核的较小修改和bug修复。
微调次数表示对内核的微小修改或补丁。
发布类型:Linux内核的发布类型可以分为稳定版和开发版。
稳定版是经过充分测试和发布的版本,用于生产环境。
开发版则用于开发和测试新的功能和代码,可能包含一些新的特性和功能,但也可能存在一些不稳定的问题。
根据不同的分类标准,Linux内核有很多不同的版本。
例如,按照版本号的编号方式,可以分为基于时间的版本号和基于内容的版本号。
基于时间的版本号是根据发布时间来编号的,例如0.01、0.02、0.10等。
基于内容的版本号是根据内核的功能和特性来编号的,例如A.B.C.D的格式。
此外,Linux内核还有很多具体的版本,例如1.0、2.4、3.0等。
其中,1.0是Linux内核的第一个正式版本,2.4和2.6都是稳定版的内核,而3.0及以上版本则是新的主版本号,表示内核的重大更新。
linux启动文件设置编码规则
linux启动文件设置编码规则
在Linux系统中,启动文件的编码规则通常是使用UTF-8编码。
UTF-8是一种Unicode字符编码方案,它支持全球范围内的几乎所
有字符,包括中文、日文、韩文等。
在Linux系统中,UTF-8编码
已成为默认的字符编码方式,因为它能够很好地兼容各种语言的字符,并且能够在不同平台之间进行良好的交互和传输。
启动文件通常指的是一些重要的系统文件,比如启动脚本、配
置文件等,这些文件的编码规则也应该遵循UTF-8编码。
这样做的
好处是可以确保系统能够正确地读取和处理其中的字符,避免出现
乱吗或者编码错误的情况。
另外,使用UTF-8编码也有助于提高文
件的可移植性和兼容性,因为UTF-8编码在不同的操作系统和软件
中都得到了广泛的支持。
除了UTF-8编码之外,有些特定的启动文件可能还会使用其他
编码规则,比如配置文件可能会使用INI格式或者XML格式,这些
格式本身也会规定其字符编码方式。
在这种情况下,需要根据文件
的实际格式和要求来选择合适的编码规则。
总之,在Linux系统中,启动文件的编码规则一般应该遵循
UTF-8编码,这样可以确保系统的稳定性和可移植性。
当然,在实际应用中还需要根据具体情况来选择合适的编码规则,以确保文件能够被正确地读取和处理。
Linux操作系统源代码详细分析报告
Linux操作系统源代码详细分析容简介:Linux 拥有现代操作系统所有的功能,如真正的抢先式多任务处理、支持多用户,存保护,虚拟存,支持SMP、UP,符合POSIX标准,联网、图形用户接口和桌面环境。
具有快速性、稳定性等特点。
本书通过分析Linux的核源代码,充分揭示了Linux作为操作系统的核是如何完成保证系统正常运行、协调多个并发进程、管理存等工作的。
现实中,能让人自由获取的系统源代码并不多,通过本书的学习,将大大有助于读者编写自己的新程序。
第一部分 Linux 核源代码arch/i386/kernel/entry.S 2arch/i386/kernel/init_task.c 8arch/i386/kernel/irq.c 8arch/i386/kernel/irq.h 19arch/i386/kernel/process.c 22arch/i386/kernel/signal.c 30arch/i386/kernel/smp.c 38arch/i386/kernel/time.c 58arch/i386/kernel/traps.c 65arch/i386/lib/delay.c 73arch/i386/mm/fault.c 74arch/i386/mm/init.c 76fs/binfmt-elf.c 82fs/binfmt_java.c 96fs/exec.c 98include/asm-generic/smplock.h 107include/asm-i386/atomic.h 108include/asm-i386/current.h 109include/asm-i386/dma.h 109include/asm-i386/elf.h 113include/asm-i386/hardirq.h 114include/asm-i386/page.h 114include/asm-i386/pgtable.h 115include/asm-i386/ptrace.h 122include/asm-i386/semaphore.h 123include/asm-i386/shmparam.h 124include/asm-i386/sigcontext.h 125include/asm-i386/siginfo.h 125include/asm-i386/signal.h 127include/asm-i386/smp.h 130include/asm-i386/softirq.h 132include/asm-i386/spinlock.h 133include/asm-i386/system.h 137include/asm-i386/uaccess.h 139include/linux/capability.h 147 include/linux/elf.h 150include/linux/elfcore.h 156 include/linux/interrupt.h 157 include/linux/kernel.h 158 include/linux/kernel_stat.h 159 include/linux/limits.h 160 include/linux/mm.h 160include/linux/module.h 164 include/linux/msg.h 168include/linux/personality.h 169 include/linux/reboot.h 169 include/linux/resource.h 170 include/linux/sched.h 171 include/linux/sem.h 179include/linux/shm.h 180include/linux/signal.h 181 include/linux/slab.h 184 include/linux/smp.h 184include/linux/smp_lock.h 185 include/linux/swap.h 185 include/linux/swapctl.h 187 include/linux/sysctl.h 188 include/linux/tasks.h 194 include/linux/time.h 194 include/linux/timer.h 195 include/linux/times.h 196 include/linux/tqueue.h 196 include/linux/wait.h 198init/main.c 198init/version.c 212ipc/msg.c 213ipc/sem.c 218ipc/shm.c 227ipc/util.c 236kernel/capability.c 237kernel/dma.c 240kernel/exec_domain.c 241kernel/exit.c 242kernel/fork.c 248kernel/info.c 255kernel/itimer.c 255kernel/kmod.c 257kernel/module.c 259kernel/panic.c 270kernel/sched.c 275kernel/signal.c 295kernel/softirq.c 307kernel/sys.c 307kernel/sysctl.c 318kernel/time.c 330mm/memory.c 335mm/mlock.c 345mm/mmap.c 348mm/mprotect.c 358mm/mremap.c 361mm/page_alloc.c 363mm/page_io.c 368mm/slab.c 372mm/swap.c 394mm/swap_state.c 395mm/swapfile.c 398mm/vmalloc.c 406mm/vmscan.c 409第二部分 Linux 核源代码分析第1章 Linux 简介让用户很详细地了解大多数现有操作系统的实际工作方式是不可能的,因为大多数操作系统的源代码都是严格的。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
这是翻译版本,英文原版是linux源码Documentation文件夹下的CodingStyle一个良好风格的程序看起来直观、美观,便于阅读,还能有助于对程序的理解,特别在代码量比较大情况下更显现编码素质的重要性。
相反没有良好的风格的代码读起来难看、晦涩,甚至有时候一个括号没对齐就能造成对程序的曲解或者不理解。
我曾经就遇见过这样的情况,花费了很多不必要的时间在程序的上下文对照上,还debug了半天没理解的程序。
后来直接用indent -kr -i8给他转换格式来看了。
特此转过来一个关于代码风格的帖子分享一下~Linux内核编码风格这是一份简短的,描述linux内核首选编码风格的文档。
编码风格是很个人化的东西,而且我也不愿意把我的观点强加给任何人,不过这里所讲述的是我必须要维护的代码所遵守的风格,并且我也希望绝大多数其他代码也能遵守这个风格。
所以请至少考虑一下本文所述的观点。
首先,我建议你打印一份GNU的编码规范,然后不要读它。
烧掉它,这是一个很高调的具有象征意义的姿态。
Anyway, here goes:第一章:缩进制表符是8个字符,所以缩进也是8个字符。
有些异端运动试图将缩进变为4(乃至2)个字符深,这跟尝试着将圆周率PI的值定义为3没什么两样。
理由:缩进的全部意义就在于清楚的定义一个控制块起止于何处。
尤其是当你盯着你的屏幕连续看了20小时之后,你将会发现大一点的缩进将会使你更容易分辨缩进。
现在,有些人会抱怨8个字符的缩进会使代码向右边移动的太远,在80个字符的终端屏幕上就很难读这样的代码。
这个问题的答案是,如果你需要3级以上的缩进,不管缩进深度如何你的代码已经有问题了,应该修正你的程序。
简而言之,8个字符的缩进可以让代码更容易阅读,还有一个好处是当你的函数嵌套太深的时候可以向你提出告警。
请留意这个警告。
在switch语句中消除多级缩进的首选的方式是让“switch”和从属于它的“case”标签对齐于同一列,而不要“两次缩进”“case”标签。
比如:switch (suffix) {case 'G':case 'g':mem <<= 30;break;case 'M':case 'm':mem <<= 20;break;case 'K':case 'k':mem <<= 10;/* fall through */default:break;}不要把多个语句放在一行里,除非你有什么东西要隐藏:if (condition) do_this;do_something_everytime;也不要在一行里放多个赋值语句。
内核编码风格超级简单。
就是请避免使用怪异的表达式。
除了注释、文档和Kconfig之外,不要使用空格来缩进,前面的例子是例外,是有意为之。
选用一个好的编辑器,不要在行尾留空格。
第二章:把长的行和字符串打散编码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。
每一行的长度的限制是80列,我们强烈建议您遵守这个惯例。
长于80列的语句要打散成有意义的片段。
每个片段要明显短于原来的语句,而且放置的位置也明显的靠右。
同样的规则也适用于有很长参数列表的函数头。
长字符串也要打散成较短的字符串。
唯一的例外是超过80列可以大幅度提高可读性并且不会隐藏信息的情况。
void fun(int a, int b, int c){if (condition)printk(KERN_WARNING "Warning this is a long printk with ""3 parameters a: %u b: %u ""c: %u \n", a, b, c);elsenext_statement;}第三章:大括号和空格的放置C语言风格中另外一个常见问题是大括号的放置。
和缩进大小不同,选择或弃用某种放置策略并没有多少技术上的原因,不过首选的方式,就像Kernighan和Ritchie展示给我们的,是把起始大括号放在行尾,而把结束大括号放在行首,所以:if (x is true) {we do y}这适用于所有的非函数语句块(if、switch、for、while、do)。
比如:switch (action) {case KOBJ_ADD:return "add";case KOBJ_REMOVE:return "remove";case KOBJ_CHANGE:return "change";default:return NULL;}不过,有一种特殊情况,命名函数:它们的起始大括号放置于下一行的开头,这样:int function(int x){body of function}全世界的异端可能会抱怨这个不一致性,呃…确实是不一致的,不过所有思维健全的人都知道(a)K&R是正确的,并且(b)K&R是正确的。
另外,不管怎样函数都是特殊的(在C语言中,函数是不能嵌套的)。
注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,比如说do语句中的“while”或者if语句中的“else”,像这样:do {body of do-loop} while (condition);和if (x == y) {..} else if (x > y) {...} else {....}理由:K&R。
也请注意这种大括号的放置方式还能使空(或者差不多空的)行的数量最小化,同时不失可读性。
因此,由于你的屏幕上的新行的供应不是可回收的资源(想想25行的终端屏幕),你将会有更多的空行来放置注释。
仅有一个单独的语句时,不用加不必要的大括号。
if (condition)action();这点不适用于本身为某个条件语句的一个分支的单独语句。
这时应该两个分支里都使用大括号。
if (condition) {do_this();do_that();} else {otherwise();}3.1:空格Linux内核的空格使用方格(主要)取决于它是用于函数还是关键字。
(大多数)关键字后要加一个空格。
值得注意的例外是sizeof、typeof、alignof和__attribute__,这些关键字在一定程度上看起来更像函数(它们在Linux里也常常伴随小括号使用,尽管在C语言里这样的小括号不是必需的,就像“struct fileinfo info”声明过后的“sizeof info”)所以在这些关键字之后放一个空格:if, switch, case, for, do, while但是不在sizeof、typeof、alignof或者__attribute__这些关键字之后放空格。
例如, s = sizeof(struct file);不要在小括号里的表达式两侧加空格。
这是一个反例:s = sizeof( struct file );当声明指针类型或者返回指针类型的函数时,“*”的首选使用方式是使之靠近变量名或者函数名,而不是靠近类型名。
例子:char *linux_banner;unsigned long long memparse(char *ptr, char **retptr);char *match_strdup(substring_t *s);在大多数二元和三元操作符两侧使用一个空格,例如下面所有这些操作符:= + - < > * / % | & ^ <= >= == != ? :但是一元操作符后不要加空格:& * + - ~ ! sizeof typeof alignof __attribute__ defined后缀自增和自减一元操作符前不加空格:++ --前缀自增和自减一元操作符后不加空格:++ --“.”和“->”结构体成员操作符前后不加空格。
不要在行尾留空白。
有些可以自动缩进的编辑器会在新行的行首加入适量的空白,然后你就可以直接在那一行输入代码。
不过假如你最后没有在那一行输入代码,有些编辑器就不会移除已经加入的空白,就像你故意留下一个只有空白的行。
包含行尾空白的行就这样产生了。
当Git发现补丁包含了行尾空白的时候会警告你,并且可以应你的要求去掉行尾空白;不过如果你是正在打一系列补丁,这样做会导致后面的补丁失败,因为你改变了补丁的上下文。
第四章:命名C 是一个简朴的语言,你的命名也应该这样。
和Modula-2和Pascal程序员不同,C程序员不使用类似ThisVariableIsATemporaryCounter这样华丽的名字。
C程序员会称那个变量为“tmp”,这样写起来会更容易,而且至少不会令其难于理解。
不过,虽然混用大小写的名字是不提倡使用的,但是全局变量还是需要一个具描述性的名字。
称一个全局函数为“foo”是一个难以饶恕的错误。
全局变量(只有当你真正需要它们的时候再用它)需要有一个具描述性的名字,就像全局函数。
如果你有一个可以计算活动用户数量的函数,你应该叫它“count_ac tive_users()”或者类似的名字,你不应该叫它“cntuser()”。
在函数名中包含函数类型(所谓的匈牙利命名法)是脑子出了问题——编译器知道那些类型而且能够检查那些类型,这样做只能把程序员弄糊涂了。
难怪微软总是制造出有问题的程序。
本地变量名应该简短,而且能够表达相关的含义。
如果你有一些随机的整数型的循环计数器,它应该被称为“i”。
叫它“loop_counter”并无益处,如果它没有可能被误解的话。
类似的“tmp”可以用来称呼任意类型的临时变量。
如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综合症。
请看第六章(函数)。
第五章:Typedef不要使用类似“vps_t”之类的东西。
对结构体和指针使用typedef是一个错误。
当你在代码里看到:vps_t a;这代表什么意思呢?相反,如果是这样struct virtual_container *a;你就知道“a”是什么了。
很多人认为typedef“能提高可读性”。
实际不是这样的。
它们只在下列情况下有用:(a) 完全不透明的对象(这种情况下要主动使用typedef来隐藏这个对象实际上是什么)。
例如:“pte_t”等不透明对象,你只能用合适的访问函数来访问它们。
注意!不透明性和“访问函数本身”是不好的。
我们使用pte_t等类型的原因在于真的是完全没有任何共用的可访问信息。
(b) 清楚的整数类型,这样抽象层就可以帮助我们消除到底是"int"还是"long"的混淆。